feat: named case-result load combinations with full GUI support
Snapshots the current development tree, headlined by proper load combinations (user request): a reusable LoadCombination entity of weighted completed static-case results (e.g. 1.2xDead + 1.6xLive). - core: LoadCombination/LoadCombinationItem entities, Project integration (lookup, unique ids, reference validation) - services: combinations.py (linear superposition + envelope), exported via services __init__ - commands: undoable Add/Delete/Update for combinations - GUI: Load Combinations manager dialog, Run-dialog evaluation, envelope display in Results panel, Combinations tab in Table dock - tests: unit coverage (validation, math, error paths) + integration superposition check vs a single factored run
This commit is contained in:
commit
f361fee969
560 changed files with 178701 additions and 0 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
56
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
56
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
name: Bug report
|
||||
description: Report a defect in OTKO
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: A clear and concise description of the bug.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
placeholder: |
|
||||
1. Open a new project
|
||||
2. Click 'Draw Frame'
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: OTKO version
|
||||
placeholder: 0.0.1
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: python
|
||||
attributes:
|
||||
label: Python version
|
||||
placeholder: 3.11.7
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
options:
|
||||
- Windows
|
||||
- macOS
|
||||
- Linux
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Console output / traceback
|
||||
render: shell
|
||||
31
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
31
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
name: Feature request
|
||||
description: Propose a new feature or improvement
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: What engineering problem does this solve?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: phase
|
||||
attributes:
|
||||
label: Roadmap phase this fits into
|
||||
options:
|
||||
- "Phase 1 — Core Model"
|
||||
- "Phase 2 — OpenSees Service"
|
||||
- "Phase 3 — 3D Viewport"
|
||||
- "Phase 4 — Modeling Tools"
|
||||
- "Phase 5 — Properties"
|
||||
- "Phase 6 — Analysis Pipeline"
|
||||
- "Phase 7 — Post-processing"
|
||||
- "Phase 8 — Earthquake Engineering"
|
||||
- "Out of scope / new"
|
||||
26
.github/pull_request_template.md
vendored
Normal file
26
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
## Summary
|
||||
|
||||
<!-- One sentence: what does this change? -->
|
||||
|
||||
## Linked issue
|
||||
|
||||
Closes #
|
||||
|
||||
## Type of change
|
||||
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Refactor / cleanup
|
||||
- [ ] Documentation
|
||||
- [ ] CI / tooling
|
||||
|
||||
## Architectural checklist
|
||||
|
||||
- [ ] No `from PySide6` in `core/` or `services/`
|
||||
- [ ] No `import openseespy` in `core/` or `views/`
|
||||
- [ ] Public functions have type hints + docstrings
|
||||
- [ ] Heavy work runs off the GUI thread
|
||||
|
||||
## Testing
|
||||
|
||||
<!-- How was this verified? Reference tests added or analytical checks. -->
|
||||
86
.github/workflows/ci.yml
vendored
Normal file
86
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- run: pip install ruff
|
||||
- run: ruff check src tests
|
||||
- run: ruff format --check src tests
|
||||
|
||||
type:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- run: pip install -e ".[gui,dev]"
|
||||
- run: mypy src/otko/core src/otko/services src/otko/viewmodels
|
||||
|
||||
test-headless:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- 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:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- 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]"
|
||||
- name: Run GUI tests (Linux, headless)
|
||||
if: runner.os == 'Linux'
|
||||
run: xvfb-run -a pytest tests/gui
|
||||
- name: Run GUI tests (Win/Mac)
|
||||
if: runner.os != 'Linux'
|
||||
run: pytest tests/gui
|
||||
|
||||
test-integration:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- run: pip install -e ".[gui,dev]"
|
||||
- run: pytest tests/integration -m slow
|
||||
48
.github/workflows/ci.yml.disabled
vendored
Normal file
48
.github/workflows/ci.yml.disabled
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- run: pip install ruff mypy
|
||||
- run: ruff check src tests
|
||||
- run: ruff format --check src tests
|
||||
|
||||
test:
|
||||
needs: lint
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- 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 ".[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"
|
||||
63
.gitignore
vendored
Normal file
63
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Byte-compiled / optimized
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
dist/
|
||||
*.egg-info/
|
||||
*.egg
|
||||
pip-wheel-metadata/
|
||||
|
||||
# Virtual envs
|
||||
.venv/
|
||||
venv/
|
||||
env/
|
||||
|
||||
# Test / coverage
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
.coverage.*
|
||||
htmlcov/
|
||||
.cache
|
||||
.mypy_cache/
|
||||
.ruff_cache/
|
||||
|
||||
# Qt
|
||||
*.qm
|
||||
*.pyc
|
||||
.qt_for_python/
|
||||
|
||||
# Compiled .qrc → _rc.py (regenerable)
|
||||
*_rc.py
|
||||
|
||||
# IDEs
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Project artifacts
|
||||
*.log
|
||||
results/
|
||||
*.h5
|
||||
*.hdf5
|
||||
scratch/
|
||||
|
||||
# Local AI agent state (Claude Code, Cursor, etc.)
|
||||
.claude/
|
||||
.cursor/
|
||||
|
||||
# Local example WIP / verification outputs (not for the public repo)
|
||||
examples/data/Ex*_tmp/
|
||||
examples/ozan*.osmodel
|
||||
examples/ozan_results/
|
||||
/Ex*.csv
|
||||
/Ex*.png
|
||||
25
.pre-commit-config.yaml
Normal file
25
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
args: ["--maxkb=500"]
|
||||
- id: check-merge-conflict
|
||||
- id: mixed-line-ending
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.4.4
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix]
|
||||
- id: ruff-format
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.10.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
additional_dependencies: [pydantic, numpy]
|
||||
files: ^src/otko/(core|services|viewmodels)/
|
||||
58
AGENTS.md
Normal file
58
AGENTS.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# AGENTS.md — otko
|
||||
|
||||
Pre-alpha SAP2000-style desktop GUI for OpenSeesPy. Python 3.10+; **Windows requires 3.12+** (`openseespywin==3.8.0.0` has no 3.11 wheel). Solver pinned: `openseespy==3.8.0.0`.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
pip install -e ".[gui,dev]" # desktop: Qt + PyVista + 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)
|
||||
```
|
||||
|
||||
`scipy`/`pandas` in `[gui]` extras are phantom deps (not imported as of 2026-06) — do not add imports expecting them.
|
||||
|
||||
## Architecture (enforced in review — see PR template)
|
||||
|
||||
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.
|
||||
- `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).
|
||||
|
||||
Runner emits OpenSeesPy commands in fixed order (`docs/architecture.md`): `wipe → model → node → fix → material → section → geomTransf → element → timeSeries → pattern/load → recorder → system/numberer/... → analyze`. Never reorder.
|
||||
|
||||
## Verify (in this order)
|
||||
|
||||
```bash
|
||||
ruff check src tests
|
||||
ruff format src tests # line-length 100, E501 ignored
|
||||
mypy src/otko/core src/otko/services
|
||||
pytest -m "not slow" # CI gate: lint → this, on 3.10/3.11/3.12 × ubuntu/windows/macos
|
||||
```
|
||||
|
||||
Focused runs: `pytest tests/unit` (pure logic, ms), `pytest tests/gui -k <name>` (pytest-qt, needs display), `pytest tests/integration -k <name>` (real OpenSeesPy runs). Single test: `pytest tests/unit/test_project.py::test_name -q`. Markers: `gui`, `slow`. Linux GUI tests need `xvfb-run -a pytest ...` plus system Qt libs (see `ci.yml` apt list).
|
||||
|
||||
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.
|
||||
97
CONTRIBUTING.md
Normal file
97
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Contributing
|
||||
|
||||
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 # 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 # line-length 100, E501 ignored
|
||||
mypy src/otko/core src/otko/services
|
||||
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)
|
||||
|
||||
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:`. 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.
|
||||
661
LICENSE
Normal file
661
LICENSE
Normal file
|
|
@ -0,0 +1,661 @@
|
|||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
70
NOTICE
Normal file
70
NOTICE
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# 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.
|
||||
```
|
||||
|
||||
## 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.
|
||||
195
README.md
Normal file
195
README.md
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
<p align="center">
|
||||
<img src="docs/logo.svg" alt="OTKO" width="640">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
A SAP2000-style desktop GUI for
|
||||
<a href="https://openseespydoc.readthedocs.io/">OpenSeesPy</a>.
|
||||
Draw the model, click run, look at the diagrams.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<em>Pre-alpha. Under active development. APIs and file formats will change.</em>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
## Why
|
||||
|
||||
OpenSees does nonlinear FEM well. Its user interface is a script.
|
||||
OTKO puts a visual front-end on it:
|
||||
|
||||
- Draw nodes, frames, supports, and loads on a snapped grid.
|
||||
- Assign materials, sections, and load patterns through dialogs.
|
||||
- Run static, modal, pushover, and time-history analyses with progress
|
||||
and cancel.
|
||||
- Look at the results — deformed shape, mode shapes, force
|
||||
diagrams, pushover curves, time-history plots, hysteresis loops.
|
||||
- Save the model as one `.osmodel` JSON file. Diffs cleanly in Git,
|
||||
builds cleanly from Python.
|
||||
|
||||
Underneath, the `core` Pydantic model works fine from a script or
|
||||
notebook. The GUI is a front-end, not the whole product.
|
||||
|
||||
## What works today
|
||||
|
||||
- **Modeling** — grids, nodes, frames (elastic + force-based), trusses,
|
||||
quads, zero-length sections, restraints, equalDOF constraints,
|
||||
distributed loads, ground motions (`PathTimeSeries` /
|
||||
`UniformExcitation`).
|
||||
- **Materials and sections** — `Steel01`, `Steel02`, `Concrete01`,
|
||||
`Concrete02`, `ElasticPP`, `Hysteretic`, fiber sections (rectangular /
|
||||
circular patches + rebar layers), `SectionAggregator`,
|
||||
`BeamWithHinges`.
|
||||
- **Analyses** — static (load- or displacement-controlled), modal,
|
||||
displacement-controlled pushover, transient time-history with
|
||||
mode-1 Rayleigh damping. Chained workflows: gravity preload →
|
||||
`loadConst -time 0.0` → pushover or transient.
|
||||
- **Post-processing** — deformed shape (with scale slider), animated
|
||||
mode shapes, axial / shear / moment diagrams, pushover curves
|
||||
(in display units), time-history plots, hysteresis loops,
|
||||
response-spectrum SRSS / CQC, snapshot + video export.
|
||||
- **Persistence** — one JSON `.osmodel` per project, Pydantic-validated,
|
||||
round-trips clean.
|
||||
- **Examples** — 20+ verified examples, including OpenSees
|
||||
Wiki Examples 1–4 and a fiber-section RC frame pushover.
|
||||
See [`examples/README.md`](examples/README.md).
|
||||
|
||||
## Tech stack
|
||||
|
||||
| Layer | Library |
|
||||
| ------------ | ------------------------------------ |
|
||||
| GUI | PySide6 (Qt 6) |
|
||||
| 3D viewport | PyVista + pyvistaqt (VTK) |
|
||||
| 2D plots | pyqtgraph |
|
||||
| Solver | OpenSeesPy 3.8.0.0 |
|
||||
| Numerics | NumPy |
|
||||
| Storage | Pydantic v2 (model), h5py (results) |
|
||||
| Tests | pytest, pytest-qt |
|
||||
| Lint / type | ruff, mypy |
|
||||
|
||||
## Architecture
|
||||
|
||||
Strict MVVM + service layer. `core` is pure Python — no Qt,
|
||||
no OpenSeesPy imports — and unit-tests in isolation.
|
||||
|
||||
```
|
||||
views (Qt) → viewmodels → services (OpenSeesRunner, Persistence) → core (model)
|
||||
```
|
||||
|
||||
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):
|
||||
|
||||
```bash
|
||||
git clone ssh://git@smill-home.ddns.net/smill/otko.git
|
||||
cd otko
|
||||
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate # Windows
|
||||
source .venv/bin/activate # Linux / macOS
|
||||
|
||||
pip install -e ".[gui,dev]"
|
||||
```
|
||||
|
||||
**Headless** (core + services only, no Qt):
|
||||
|
||||
```bash
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
That pulls pydantic, numpy, h5py, openseespy and nothing else.
|
||||
Use it for scripts, notebooks, and web backends that reuse
|
||||
`otko.core` or `otko.services` without the GUI.
|
||||
|
||||
Python 3.10+. On Windows use **3.12+** — `openseespywin==3.8.0.0`
|
||||
has no 3.11 wheel (`Requires-Python >=3.12`). Both pins already
|
||||
live in `pyproject.toml`.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
python -m otko
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
1. **File → Open** → `examples/cantilever.osmodel`.
|
||||
2. **Analyze → Cases** → run `Tip-Load`.
|
||||
3. **Display → Show Force Diagram** → **M3**: linear moment,
|
||||
50 kN·m at the fixed end. **V2**: constant -10 kN.
|
||||
4. **Display → Show Deformed Shape** → cantilever curve, as advertised.
|
||||
|
||||
Nonlinear version: open `examples/portal_pushover.osmodel`,
|
||||
run `Push-X`, **Display → Show Pushover Curve**. Elastic ramp,
|
||||
then a yield plateau as the base hinges form.
|
||||
|
||||
## Run the test suite
|
||||
|
||||
```bash
|
||||
pytest tests/unit # pure logic, milliseconds
|
||||
pytest tests/gui # Qt event-loop tests (pytest-qt)
|
||||
pytest tests/integration # real OpenSeesPy runs on bundled examples
|
||||
```
|
||||
|
||||
CI runs lint + the non-`slow` subset on Linux / macOS / Windows
|
||||
× Python 3.10 / 3.11 / 3.12.
|
||||
|
||||
## Roadmap
|
||||
|
||||
[`docs/roadmap.md`](docs/roadmap.md) has the phase-by-phase plan.
|
||||
Phases 0–7 (modeling, analysis, post-processing) are mostly done.
|
||||
Phase 8 (isolators, ground-motion library, IDA, fiber-section
|
||||
editor polish) is where the open work is.
|
||||
|
||||
## Collaborators wanted
|
||||
|
||||
Most useful to people who already work with OpenSees and want a
|
||||
shorter path from idea to model — and would rather build it together
|
||||
than alone. Open an issue or say hi if you are:
|
||||
|
||||
- A **structural / earthquake engineer** who knows OpenSees Tcl
|
||||
or OpenSeesPy and can tell us when a feature is almost right
|
||||
but not quite.
|
||||
- A **researcher** running pushover, IDA, or response-spectrum studies
|
||||
who can check the GUI against hand-built scripts.
|
||||
- A **Python / Qt developer** into scientific desktop apps,
|
||||
VTK rendering, or Pydantic schema design.
|
||||
- A **student** learning FEM and GUI architecture at the same time —
|
||||
the examples and tests are meant to read as documentation.
|
||||
- A **UX / icon designer** willing to argue about dialogs, toolbar
|
||||
icons, and visual language.
|
||||
|
||||
Bug reports and reproducible test cases count as contributions.
|
||||
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for setup and the rules
|
||||
enforced in review.
|
||||
|
||||
## License
|
||||
|
||||
OTKO is **GNU Affero General Public License v3.0**
|
||||
([`LICENSE`](LICENSE)). Read the license itself, not just this:
|
||||
|
||||
- Research, education, personal projects: fine, keep the copyright
|
||||
notice.
|
||||
- Fork and modify: fine.
|
||||
- Distribute it (modified or not): release your full source under
|
||||
AGPL-3.0.
|
||||
- Run a modified version as a network service: release your
|
||||
modifications under AGPL-3.0.
|
||||
|
||||
Commercial forks stay open. If you need a different arrangement
|
||||
(e.g. closed-source commercial license), open an issue.
|
||||
|
||||
Copyright © 2026 Ozan and contributors.
|
||||
132
docs/QUICK_GUIDE.md
Normal file
132
docs/QUICK_GUIDE.md
Normal 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
26
docs/README.md
Normal 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.
|
||||
331
docs/adr/ADR-0001-gidopensees-schema-import.md
Normal file
331
docs/adr/ADR-0001-gidopensees-schema-import.md
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
# ADR-0001 — Import gidopensees Schemas into OTKO
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Status** | Proposed |
|
||||
| **Date** | 2026-05-22 |
|
||||
| **Author** | ogunc |
|
||||
| **Deciders** | Core maintainers |
|
||||
| **Source project** | [gidopensees](https://github.com/rclab-auth/gidopensees) — AUTh Lab of R/C and Masonry Structures |
|
||||
|
||||
---
|
||||
|
||||
## 1. Context
|
||||
|
||||
### Why gidopensees?
|
||||
|
||||
gidopensees is the most complete published schema inventory for the OpenSees
|
||||
material/element/condition set. It covers 60+ material types, 30+ element
|
||||
types, and 31 boundary-condition and load types — all expressed as GiD
|
||||
preprocessor `.mat` / `.cnd` BOOK definitions, with DEPENDENCIES (field
|
||||
visibility rules), `#UNITS#` annotations, and TKWIDGET hooks for
|
||||
auto-fill presets and Wiki links.
|
||||
|
||||
OTKO currently supports ~34 of these objects (see
|
||||
`docs/gap-analysis-gidopensees.md`). Importing gidopensees schemas would
|
||||
close 23 P1 gaps (Phase 8 targets) and 21 P2 gaps without requiring us to
|
||||
reverse-engineer OpenSeesPy docs for each type.
|
||||
|
||||
### What we are NOT doing
|
||||
|
||||
This ADR covers **schema definitions only** — Pydantic model fields, field
|
||||
metadata, and default values. It does not cover:
|
||||
|
||||
- The `bas/` Python code-generation templates (separate ADR).
|
||||
- The `tcl/` TKWIDGET Tcl implementations (separate ADR).
|
||||
- Any runtime OpenSeesPy command emission — that lives in
|
||||
`services/opensees_runner.py` and follows naturally once a schema
|
||||
is accepted.
|
||||
|
||||
---
|
||||
|
||||
## 2. Decision
|
||||
|
||||
### 2.1 New package: `core/catalog/`
|
||||
|
||||
A new package `src/otko/core/catalog/` will hold
|
||||
gidopensees-derived schema definitions alongside curated additions.
|
||||
|
||||
```
|
||||
src/otko/core/catalog/
|
||||
├── __init__.py # re-exports curated + generated public symbols
|
||||
├── generated/ # output of the codegen tool — DO NOT edit by hand
|
||||
│ ├── _header.py # shared attribution header (inserted by codegen)
|
||||
│ ├── steel.py
|
||||
│ ├── concrete.py
|
||||
│ ├── other_uniaxial.py
|
||||
│ ├── nd_materials.py
|
||||
│ ├── sections.py
|
||||
│ └── elements.py
|
||||
└── curated/ # human-reviewed, hand-edited overrides and additions
|
||||
├── README.md # explains the curated/ contract
|
||||
└── …
|
||||
```
|
||||
|
||||
**Existing modules are untouched.** The objects in `core/materials/`,
|
||||
`core/sections/`, `core/geometry/elements.py` remain authoritative for
|
||||
every type already supported. Catalog objects enter the UI only after
|
||||
equivalence is established (see §2.7).
|
||||
|
||||
### 2.2 Codegen tool: `tools/gidopensees_import/`
|
||||
|
||||
A build-time parser + code-generator lives in
|
||||
`tools/gidopensees_import/`, outside `src/`:
|
||||
|
||||
```
|
||||
tools/gidopensees_import/
|
||||
├── README.md
|
||||
├── parse_mat.py # parses OpenSees.mat into an intermediate IR
|
||||
├── parse_cnd.py # parses OpenSees.cnd into an intermediate IR
|
||||
├── codegen.py # renders IR → Pydantic v2 model source files
|
||||
├── ir.py # intermediate representation dataclasses
|
||||
└── tests/ # unit tests for the parser and codegen
|
||||
```
|
||||
|
||||
The tool runs once per gidopensees update. Its output (`generated/`) is
|
||||
committed so CI never requires gidopensees to be present. The tool is
|
||||
invoked manually by a maintainer:
|
||||
|
||||
```bash
|
||||
python tools/gidopensees_import/codegen.py \
|
||||
--mat path/to/OpenSees.mat \
|
||||
--cnd path/to/OpenSees.cnd \
|
||||
--out src/otko/core/catalog/generated/
|
||||
```
|
||||
|
||||
**Rationale:** keeping the parser outside `src/` prevents it from being
|
||||
imported at runtime, avoids adding GiD file parsing as a dependency of
|
||||
the installable package, and makes the "run once, commit output" contract
|
||||
explicit to contributors.
|
||||
|
||||
### 2.3 Attribution
|
||||
|
||||
Every file under `core/catalog/generated/` carries this header comment
|
||||
(inserted by `codegen.py`):
|
||||
|
||||
```python
|
||||
# This file is derived from gidopensees.
|
||||
# Source: https://github.com/rclab-auth/gidopensees
|
||||
# Authors: AUTh Lab of R/C and Masonry Structures
|
||||
# (https://rclab.civil.auth.gr/)
|
||||
# Modifications: generated by tools/gidopensees_import/codegen.py
|
||||
```
|
||||
|
||||
Files under `curated/` carry a similar header when they derive from
|
||||
gidopensees content.
|
||||
|
||||
### 2.4 `.osmodel` format backward-compatibility
|
||||
|
||||
The `.osmodel` JSON format uses Pydantic discriminated unions keyed on a
|
||||
`"type"` field. New material types from `core/catalog/` appear as new
|
||||
discriminator values. The union in `core/materials/__init__.py` is
|
||||
extended only when a catalog type is promoted to stable (see §2.7).
|
||||
|
||||
Old project files that do not contain the new discriminator values load
|
||||
cleanly: Pydantic ignores unknown items in lists when
|
||||
`model_config = ConfigDict(extra="ignore")`, and the `Project` validator
|
||||
will log (not raise) on unknown type strings if we add a graceful
|
||||
fallback.
|
||||
|
||||
**Migration path:**
|
||||
1. Catalog type is added with a temporary discriminator value
|
||||
(e.g. `"catalog.Concrete04"`).
|
||||
2. After verification (§2.7) it is promoted to a stable value
|
||||
(e.g. `"Concrete04"`) and the temporary value is kept as an alias for
|
||||
one minor version.
|
||||
3. A `migrate_osmodel.py` script in `tools/` handles the rename if needed.
|
||||
|
||||
No existing `.osmodel` file ever breaks on open.
|
||||
|
||||
### 2.5 Field metadata for TKWIDGET hooks
|
||||
|
||||
gidopensees BOOK definitions contain TKWIDGET directives that fire
|
||||
auto-fill presets (e.g. `SteelUniaxMaterial::GenerateValues`), Wiki links
|
||||
(`TK_MaterialWikiInfo`), and the Material Tester dialog
|
||||
(`TK_MaterialTester`). These are deferred from this ADR.
|
||||
|
||||
Each field or model where a TKWIDGET hook is relevant carries a
|
||||
`json_schema_extra` annotation recording the hook name:
|
||||
|
||||
```python
|
||||
class Concrete04(CatalogEntity):
|
||||
...
|
||||
class model_config(ConfigDict):
|
||||
json_schema_extra = {
|
||||
"tkwidget_hooks": [
|
||||
"ConcreteUniaxMaterial::GenerateValues",
|
||||
"TK_MaterialWikiInfo",
|
||||
"TK_MaterialTester",
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This metadata is visible to future UI layers without coupling `core/` to
|
||||
Qt. Implementation of the actual preset dialogs and Wiki-link buttons
|
||||
comes in a later UI phase.
|
||||
|
||||
### 2.6 DEPENDENCIES → `dependent_schemas` metadata (not validators)
|
||||
|
||||
gidopensees BOOK DEPENDENCIES express field-visibility rules:
|
||||
|
||||
```
|
||||
(1, RESTORE, Gap_length, #CURRENT#), (0, HIDE, Gap_length, #CURRENT#)
|
||||
```
|
||||
|
||||
These are **viewmodel / UI concerns**, not data-validity rules, and
|
||||
therefore must not become Pydantic validators in `core/`.
|
||||
|
||||
Each Pydantic model that has visibility dependencies stores them as
|
||||
`json_schema_extra["dependencies"]` — a list of dicts describing the
|
||||
trigger field, trigger value, and affected fields. The viewmodel layer
|
||||
reads these at dialog-construction time to wire up the show/hide logic.
|
||||
|
||||
**Example:**
|
||||
|
||||
```python
|
||||
class ViscousDamper(CatalogEntity):
|
||||
activate_gap: Literal[0, 1] = 0
|
||||
gap_length: float | None = None
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"dependencies": [
|
||||
{"trigger": "activate_gap", "value": 1, "restore": ["gap_length"]},
|
||||
{"trigger": "activate_gap", "value": 0, "hide": ["gap_length"]},
|
||||
]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### 2.7 Unit-annotated fields (`#UNITS#`)
|
||||
|
||||
gidopensees marks numeric fields with `#UNITS#` where the value's
|
||||
interpretation is unit-system–dependent (forces in kN, lengths in m, etc.).
|
||||
|
||||
OTKO already has `core/units.py` with `UnitSystem` and
|
||||
`UnitLabels`. It does **not** currently attach unit metadata to individual
|
||||
model fields — the unit system is a project-level property and all numeric
|
||||
values are stored in the project's native unit system, with `UnitLabels`
|
||||
used only for display.
|
||||
|
||||
**Intended design:** Generated catalog models will mark unit-annotated fields
|
||||
using a `Field` `metadata` entry (Pydantic v2 `Annotated` style):
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
from pydantic import Field
|
||||
|
||||
class UnitTag:
|
||||
"""Marker for fields whose display label depends on UnitSystem."""
|
||||
def __init__(self, quantity: str):
|
||||
self.quantity = quantity # e.g. "force", "length", "stress"
|
||||
|
||||
ForceMagnitude = Annotated[float, UnitTag("force")]
|
||||
LengthValue = Annotated[float, UnitTag("length")]
|
||||
StressValue = Annotated[float, UnitTag("stress")]
|
||||
```
|
||||
|
||||
These type aliases would live in `core/catalog/_units.py`. No conversion logic
|
||||
is added to `core/`; the viewmodel layer reads `UnitTag.quantity` to
|
||||
select the right `UnitLabels` field for axis labels and input hints.
|
||||
|
||||
**Implementation status (2026-05-22) — DEFERRED:** The codegen tool does not
|
||||
yet emit `UnitTag` annotations. Fields corresponding to `#UNITS#` entries in
|
||||
the gidopensees source are currently emitted as `str` with a
|
||||
`# TODO: unit-aware type` comment preserving the gidopensees default string
|
||||
(e.g. `yield_stress_fy: str = '500 MPa' # TODO: unit-aware type`). This is
|
||||
a conscious deferral: the `str` placeholder keeps the field present and
|
||||
round-trippable without binding the codebase to a unit-system convention that
|
||||
is not yet finalised. A dedicated unit-system layer — covering `UnitTag`,
|
||||
`_units.py`, and viewmodel wiring — is tracked as future work and will be
|
||||
addressed in a follow-up ADR before any `#UNITS#` field is promoted to stable.
|
||||
|
||||
**If this convention is inadequate** (e.g. if we need per-field unit
|
||||
conversion in the future), a follow-up ADR should address it before
|
||||
the convention is applied beyond `catalog/`.
|
||||
|
||||
### 2.8 Verification plan
|
||||
|
||||
A catalog type is promoted from generated → stable only when **all three**
|
||||
of the following are satisfied:
|
||||
|
||||
1. **Schema equivalence test** (`tests/unit/catalog/test_<name>_schema.py`):
|
||||
Constructs a model instance with the same arguments as the
|
||||
corresponding Tcl example from the OpenSees Wiki and asserts that
|
||||
`model.model_dump()` produces the expected dict. No OpenSeesPy import.
|
||||
|
||||
2. **Round-trip test** (`tests/unit/catalog/test_<name>_roundtrip.py`):
|
||||
Serialises the model to JSON (`.osmodel` fragment), deserialises it
|
||||
back, and asserts equality. Confirms the discriminator and all field
|
||||
aliases survive the round-trip.
|
||||
|
||||
3. **Integration smoke test** (`tests/integration/catalog/test_<name>.py`):
|
||||
Builds a minimal project using the new type, runs it through
|
||||
`OpenSeesRunner`, and checks that the runner does not raise and that at
|
||||
least one result quantity (reaction, displacement, or force) is finite.
|
||||
Tagged `@pytest.mark.slow` and skipped if `openseespy` is not installed.
|
||||
|
||||
Manual review checklist (for the PR that promotes a type):
|
||||
|
||||
- [ ] Attribution header present in the generated file.
|
||||
- [ ] `json_schema_extra["tkwidget_hooks"]` populated where applicable.
|
||||
- [ ] `json_schema_extra["dependencies"]` populated for every DEPENDENCY
|
||||
in the source BOOK.
|
||||
- [ ] `#UNITS#` fields use the correct `UnitTag` quantity string.
|
||||
- [ ] The type discriminator value does not collide with any existing type
|
||||
in `core/materials/__init__.py`, `core/sections/__init__.py`, or
|
||||
`core/geometry/elements.py`.
|
||||
- [ ] The integration smoke test result has been spot-checked against the
|
||||
gidopensees wiki reference or an independent OpenSees Tcl run.
|
||||
|
||||
---
|
||||
|
||||
## 3. Alternatives considered
|
||||
|
||||
### 3A: Extend existing `core/materials/__init__.py` directly
|
||||
|
||||
Rejected. The existing module is small and well-tested; adding 60+
|
||||
unverified types creates noise and makes equivalence tracking harder.
|
||||
A separate `catalog/` namespace keeps the boundary clear.
|
||||
|
||||
### 3B: Use gidopensees at runtime (import `.mat` on startup)
|
||||
|
||||
Rejected. The GiD BOOK format is proprietary and requires the GiD parser.
|
||||
Depending on gidopensees at runtime adds a third-party dependency to the
|
||||
installed package and makes offline / air-gapped installs harder. The
|
||||
codegen + committed-output approach keeps the package dependency-clean.
|
||||
|
||||
### 3C: Hand-write every new type without the codegen tool
|
||||
|
||||
Would work but loses the systematic relationship between gidopensees
|
||||
DEPENDENCIES / TKWIDGET metadata and the Pydantic model. The codegen
|
||||
pipeline preserves that metadata structurally so UI implementors can
|
||||
reference it rather than re-reading `.mat` files.
|
||||
|
||||
---
|
||||
|
||||
## 4. Risks
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|---|---|---|---|
|
||||
| Namespace collision between `catalog/` and existing `core/` types | Medium | Medium | Verify discriminator values before promotion; CI check added to the merge checklist |
|
||||
| gidopensees schema drift (upstream changes `.mat`) | Low | Medium | `generated/` is committed; only re-run codegen intentionally; diff the output and add a CHANGELOG entry |
|
||||
| Testing surface explosion (60+ new types × 3 test tiers) | High | Low | Only promoted types get full test coverage; generated-but-not-yet-promoted types have schema + round-trip tests only |
|
||||
| Attribution omission | Low | High | Codegen always inserts the header; a pre-commit hook (`grep -r "rclab-auth/gidopensees" core/catalog/generated/` must pass) enforces it |
|
||||
| `#UNITS#` convention inadequacy | Medium | Medium | Convention is isolated to `core/catalog/_units.py`; a follow-up ADR can replace it without touching existing `core/` code |
|
||||
|
||||
---
|
||||
|
||||
## 5. Out of scope for this ADR
|
||||
|
||||
- `bas/` Python template parsing and code generation (separate ADR).
|
||||
- `tcl/` TKWIDGET Tcl implementations (separate ADR).
|
||||
- Seismic isolator element schemas (`elastomericBearing*`,
|
||||
`frictionPendulumBearing`, etc.) — those are new elements, not directly
|
||||
in the gidopensees BOOK format; they get their own ADR.
|
||||
- IDA batch runner (analysis feature, not schema).
|
||||
- Fiber-section visual editor UI polish (UI feature, not schema).
|
||||
- The OpenSeesPy command emission side — `services/opensees_runner.py`
|
||||
will need updates for each promoted type, but those changes follow
|
||||
naturally from the schema and are reviewed in the same PR as the
|
||||
integration smoke test.
|
||||
91
docs/adr/ADR-0002-headless-gui-dep-split.md
Normal file
91
docs/adr/ADR-0002-headless-gui-dep-split.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# ADR-0002 — Split pyproject dependencies into headless base and `gui` optional extra
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Status** | Accepted |
|
||||
| **Date** | 2026-06-15 |
|
||||
| **Author** | ogunc |
|
||||
|
||||
---
|
||||
|
||||
## 1. Context
|
||||
|
||||
`otko.core` is pure Pydantic v2 (no Qt, no OpenSeesPy imports — stated
|
||||
explicitly in `core/__init__.py`). `otko.services` adds NumPy, h5py, and
|
||||
OpenSeesPy for headless computation. Together, these two packages can be used from
|
||||
scripts, Jupyter notebooks, and web backends **without any Qt or 3D-rendering stack**.
|
||||
|
||||
Before this ADR, every `pip install otko` pulled in PySide6, pyvista,
|
||||
pyvistaqt, vtk, pyqtgraph, and imageio — roughly 800 MB of GUI/visualization
|
||||
packages — even when only the headless computation layer was needed. Web backends and
|
||||
CI machines without a display had to work around this with `--no-deps`, which is
|
||||
fragile and skips genuine compute-layer deps (numpy, h5py) too.
|
||||
|
||||
## 2. Decision
|
||||
|
||||
Split `[project.dependencies]` into two tiers in `pyproject.toml`:
|
||||
|
||||
### Headless base (`pip install -e .`)
|
||||
|
||||
Packages imported by `core/` and the non-Qt parts of `services/`:
|
||||
|
||||
| Package | Where used |
|
||||
|---------|-----------|
|
||||
| `pydantic>=2.5` | All `core/` modules, `material_tester.py` |
|
||||
| `numpy>=1.26` | `services/` computation modules (7 files) |
|
||||
| `h5py>=3.10` | `opensees_runner._run_transient()`, `TransientResults` accessors |
|
||||
| `openseespy==3.8.0.0` | Lazy import in `OpenSeesRunner.__init__` |
|
||||
| `openseespywin==3.8.0.0 ; sys_platform=='win32'` | Windows DLL companion |
|
||||
|
||||
### GUI extra (`pip install -e ".[gui]"`)
|
||||
|
||||
Packages only needed by `views/`, `viewmodels/`, `commands/`, `qt_workers.py`,
|
||||
and `animation_export.py` (which drives a live PyVista plotter):
|
||||
|
||||
`PySide6`, `pyvista`, `pyvistaqt`, `vtk`, `pyqtgraph`, `imageio[ffmpeg]`,
|
||||
`scipy` (forward-compat, currently a phantom dep), `pandas` (same).
|
||||
|
||||
## 3. Consequences
|
||||
|
||||
- **Desktop developers** install with `pip install -e ".[gui,dev]"`. No change to
|
||||
what gets installed; only the install command changes from `.[dev]` → `.[gui,dev]`.
|
||||
- **Web backends / scripts / notebooks** install with `pip install -e .` (or
|
||||
`pip install otko`) and get a lean ~50 MB environment.
|
||||
- **otko-web** can drop the `--no-deps` workaround and install the
|
||||
package normally. The web backend's `requirements.txt` no longer needs to list
|
||||
pydantic/numpy/h5py separately — they come from the base install.
|
||||
- **scipy and pandas** are listed under `[gui]` as phantom deps (currently never
|
||||
imported anywhere in the codebase). They are kept to avoid surprise breakage if a
|
||||
future feature adds them; audited and flagged on 2026-06-15.
|
||||
|
||||
## 4. Verification
|
||||
|
||||
After installing only the base set:
|
||||
|
||||
```python
|
||||
import sys
|
||||
from otko.core import Project
|
||||
from otko.services.opensees_runner import OpenSeesRunner
|
||||
from otko.services.material_tester import test_uniaxial_material
|
||||
|
||||
# Run a modal analysis on the bundled two-storey shear frame example
|
||||
import json
|
||||
from pathlib import Path
|
||||
from otko.core import ModalCase
|
||||
|
||||
data = json.loads(Path("examples/eigen_two_storey_shear_frame.osmodel").read_text())
|
||||
project = Project.model_validate(data)
|
||||
modal_case = next(c for c in project.analyses if isinstance(c, ModalCase))
|
||||
runner = OpenSeesRunner(project)
|
||||
runner.build()
|
||||
results = runner._run_modal(modal_case)
|
||||
|
||||
assert len(results.eigenvalues) == 2
|
||||
assert all(ev > 0 for ev in results.eigenvalues)
|
||||
|
||||
gui_packages = {"PySide6", "pyvista", "pyvistaqt", "vtk", "pyqtgraph"}
|
||||
assert not gui_packages.intersection(sys.modules), \
|
||||
f"GUI package imported: {gui_packages & sys.modules.keys()}"
|
||||
|
||||
print("PASS — headless modal analysis complete, no GUI packages imported")
|
||||
```
|
||||
80
docs/architecture.md
Normal file
80
docs/architecture.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# Architecture
|
||||
|
||||
## Layering
|
||||
|
||||
OTKO uses a strict **MVVM + service layer** architecture. Dependencies
|
||||
flow in **one direction only**: outer layers may depend on inner layers, never
|
||||
the reverse.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ views/ Qt widgets, dialogs, 3D canvas — PySide6 only │
|
||||
│ ▲ │
|
||||
│ │ signals/slots, viewmodel binding │
|
||||
│ viewmodels/ Qt-aware adapters, QUndoStack, selection state │
|
||||
│ ▲ │
|
||||
│ │ pure Python calls │
|
||||
│ services/ OpenSeesRunner, PersistenceService, Results │
|
||||
│ ▲ │
|
||||
│ │ │
|
||||
│ core/ Project, Node, Element, Material — pure Python │
|
||||
│ NO Qt imports. NO openseespy imports. │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Why this matters
|
||||
|
||||
- `core` tests without a display server, without OpenSees, without Qt.
|
||||
CI runs `pytest tests/unit/` in milliseconds.
|
||||
- Swapping solvers (e.g. `xara`, a future fork) touches
|
||||
`services/opensees_runner.py` and nothing else.
|
||||
- A future CLI or notebook front-end reuses `core` and `services` as-is.
|
||||
|
||||
## Package map
|
||||
|
||||
| Package | Responsibility | Allowed imports |
|
||||
|---|---|---|
|
||||
| `core` | Domain entities and invariants | stdlib, numpy, pydantic |
|
||||
| `services` | I/O, solver invocation, persistence | core + stdlib + h5py + openseespy |
|
||||
| `viewmodels` | Bridge core ↔ Qt; expose Qt signals; manage undo/redo | core, services, PySide6 |
|
||||
| `views` | Pure UI; no business logic | PySide6, pyvistaqt, viewmodels |
|
||||
| `commands` | `QUndoCommand` subclasses; mutate model via services | services, viewmodels |
|
||||
|
||||
## Threading
|
||||
|
||||
The Qt main thread owns all widgets. Heavy computation happens elsewhere:
|
||||
|
||||
- **OpenSees analysis** runs in a `QThread` worker (`services.opensees_runner.AnalysisWorker`).
|
||||
- The worker emits `progress(int)`, `log(str)`, `finished(ResultsHandle)` signals.
|
||||
- The worker checks `QThread.currentThread().isInterruptionRequested()` between
|
||||
analysis steps so the user can cancel.
|
||||
- Results are written to HDF5; only a lightweight `ResultsHandle` (file path +
|
||||
metadata) crosses the thread boundary.
|
||||
|
||||
## Persistence
|
||||
|
||||
- Project files: `*.osmodel` — a JSON document validated by Pydantic models.
|
||||
Human-readable, diff-able, version-controllable.
|
||||
- Results files: `*.osresults.h5` — HDF5; one group per analysis case; datasets
|
||||
for displacements, reactions, element forces, stresses.
|
||||
|
||||
## OpenSeesPy command sequencing
|
||||
|
||||
`OpenSeesRunner` always emits commands in this order; the model layer enforces
|
||||
that all required pieces exist before a run can be requested:
|
||||
|
||||
1. `wipe()` and `model('basic', '-ndm', ndm, '-ndf', ndf)`
|
||||
2. `node(...)` for every node
|
||||
3. `fix(...)` for every restrained DOF
|
||||
4. `uniaxialMaterial(...)` / `nDMaterial(...)`
|
||||
5. `section(...)` (if used)
|
||||
6. `geomTransf(...)` for frame elements
|
||||
7. `element(...)` for every element
|
||||
8. `timeSeries(...)`
|
||||
9. `pattern(...)` with nested `load(...)`
|
||||
10. `recorder(...)`
|
||||
11. `system / numberer / constraints / integrator / algorithm / analysis`
|
||||
12. `analyze(...)`
|
||||
|
||||
Any deviation from this order is a runtime error in OpenSees. The runner
|
||||
asserts the order at the service boundary; the UI never has to think about it.
|
||||
221
docs/gap-analysis-gidopensees.md
Normal file
221
docs/gap-analysis-gidopensees.md
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
# Gap Analysis — OTKO vs gidopensees
|
||||
|
||||
**Source:** `D:\GitHub\gidopensees` (AUTh Lab of R/C and Masonry Structures)
|
||||
**Scope:** Material / section / element / constraint / load / damping schema coverage.
|
||||
**Date:** 2026-05-22
|
||||
|
||||
## How to read this table
|
||||
|
||||
| Column | Meaning |
|
||||
|---|---|
|
||||
| **Category** | Schema group (material family, element type, etc.) |
|
||||
| **Object** | Name as it appears in gidopensees BOOK/CONDITION |
|
||||
| **OTKO name** | Corresponding class in `core/` (if any) |
|
||||
| **In OTKO?** | ✅ fully supported · 🟡 partial · ❌ missing |
|
||||
| **In gidopensees?** | ✅ · ❌ |
|
||||
| **Priority** | P0 = already done · P1 = Phase 8 target · P2 = later |
|
||||
|
||||
Priority rationale:
|
||||
- **P0** — already shipped; included for completeness.
|
||||
- **P1** — high-value for earthquake-engineering practice; aligns with Phase 8
|
||||
roadmap items (isolators, Rayleigh per-region, confined concrete models,
|
||||
shell elements, floor diaphragm constraints).
|
||||
- **P2** — valid but lower-frequency in typical EQ-engineering workflows
|
||||
(soil p-y/t-z/q-z springs, 3-D solid elements, multi-yield plasticity,
|
||||
contact elements).
|
||||
|
||||
---
|
||||
|
||||
## 1. Uniaxial Materials
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Uniaxial / linear | Elastic | `ElasticUniaxial` | ✅ | ✅ | P0 |
|
||||
| Uniaxial / elastic-plastic | Elastic_Perfectly_Plastic | `ElasticPP` | ✅ | ✅ | P0 |
|
||||
| Uniaxial / elastic-plastic | Elastic_Perfectly_Plastic_with_Gap | — | ❌ | ✅ | P1 |
|
||||
| Uniaxial / damper | Viscous | — | ❌ | ✅ | P1 |
|
||||
| Uniaxial / damper | Viscous_Damper (Maxwell) | — | ❌ | ✅ | P1 |
|
||||
| Uniaxial / gap | Hyperbolic_Gap | — | ❌ | ✅ | P2 |
|
||||
| Uniaxial / soil | PySimple1 | — | ❌ | ✅ | P2 |
|
||||
| Uniaxial / soil | TzSimple1 | — | ❌ | ✅ | P2 |
|
||||
| Uniaxial / soil | QzSimple1 | — | ❌ | ✅ | P2 |
|
||||
| Uniaxial / bond-slip | BondSP01 | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 2. Steel Uniaxial Materials
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Steel | Steel01 | `Steel01` | ✅ | ✅ | P0 |
|
||||
| Steel | Steel02 | `Steel02` | ✅ | ✅ | P0 |
|
||||
| Steel | Hysteretic | `HystereticMaterial` | ✅ | ✅ | P0 |
|
||||
| Steel | Reinforcing_steel (DoDD-Restrepo) | — | ❌ | ✅ | P1 |
|
||||
| Steel | Ramberg-Osgood_steel | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 3. Concrete Uniaxial Materials
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Concrete | Concrete01_(Zero_tensile_strength) | `Concrete01` | ✅ | ✅ | P0 |
|
||||
| Concrete | Concrete02_(Linear_tension_softening) | `Concrete02` | ✅ | ✅ | P0 |
|
||||
| Concrete | Concrete04_(Popovics) | — | ❌ | ✅ | P1 |
|
||||
| Concrete | Concrete06 | — | ❌ | ✅ | P2 |
|
||||
| Concrete | ConcreteCM (Chang-Mander) | — | ❌ | ✅ | P1 |
|
||||
|
||||
## 4. Combined Materials
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Combination | Series | — | ❌ | ✅ | P1 |
|
||||
| Combination | Parallel | — | ❌ | ✅ | P1 |
|
||||
| Combination | Section_Aggregator (in .mat) | `SectionAggregator` | ✅ | ✅ | P0 |
|
||||
|
||||
## 5. nD (Multi-dimensional) Materials
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| nD | Elastic_Isotropic | `ElasticIsotropic` | ✅ | ✅ | P0 |
|
||||
| nD | Elastic_Orthotropic | — | ❌ | ✅ | P2 |
|
||||
| nD | J2Plasticity | — | ❌ | ✅ | P2 |
|
||||
| nD | Damage2p | — | ❌ | ✅ | P2 |
|
||||
| nD | PressureIndependMultiYield | — | ❌ | ✅ | P2 |
|
||||
| nD | PressureDependMultiYield | — | ❌ | ✅ | P2 |
|
||||
| nD | PressureDependMultiYield02 | — | ❌ | ✅ | P2 |
|
||||
| nD | Contact | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 6. Sections
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Section | Elastic_Section | `ElasticSection` | ✅ | ✅ | P0 |
|
||||
| Section | Fiber | `FiberSection` | ✅ | ✅ | P0 |
|
||||
| Section | Fiber_Custom | `FiberSection` (manual fibres) | 🟡 | ✅ | P0 |
|
||||
| Section | FiberInt (interaction P-M) | — | ❌ | ✅ | P1 |
|
||||
| Section | Plate_Fiber | — | ❌ | ✅ | P2 |
|
||||
| Section | Elastic_Membrane_Plate | — | ❌ | ✅ | P2 |
|
||||
| Section | LayeredShell | — | ❌ | ✅ | P2 |
|
||||
| Section | Section_Aggregator | `SectionAggregator` | ✅ | ✅ | P0 |
|
||||
|
||||
## 7. Beam-Column Elements
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Frame | Elastic_Beam-Column | `ElasticBeamColumn` | ✅ | ✅ | P0 |
|
||||
| Frame | Elastic_Timoshenko_Beam-Column | — | ❌ | ✅ | P1 |
|
||||
| Frame | Force-Based_Beam-Column | `ForceBeamColumn` | ✅ | ✅ | P0 |
|
||||
| Frame | Displacement-Based_Beam-Column | `DispBeamColumn` | ✅ | ✅ | P0 |
|
||||
| Frame | Flexure-Shear_Interaction_DispBeamColumn | — | ❌ | ✅ | P2 |
|
||||
| Frame | BeamWithHinges | `BeamWithHingesElement` | ✅ | ❌ | P0 |
|
||||
|
||||
## 8. Truss Elements
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Truss | Truss | `TrussElement` | ✅ | ✅ | P0 |
|
||||
| Truss | Corotational_Truss | `CorotTrussElement` | ✅ | ✅ | P0 |
|
||||
|
||||
## 9. Surface / Plate Elements
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Surface | Quad | `QuadElement` | ✅ | ✅ | P0 |
|
||||
| Surface | Shell (ShellMITC4 / MITC4) | — | ❌ | ✅ | P1 |
|
||||
| Surface | ShellDKGQ | — | ❌ | ✅ | P1 |
|
||||
| Surface | Tri31 | — | ❌ | ✅ | P2 |
|
||||
| Surface | QuadUP (u-p pore pressure) | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 10. Solid Elements
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Solid | Standard_Brick_Element | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 11. Zero-Length / Special Elements
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Special | Auto_Zero_Length (per-DOF uniaxial) | `ZeroLengthElement` | ✅ | ✅ | P0 |
|
||||
| Special | Auto_equal_constraint (auto equalDOF) | `EqualDOFConstraint` | ✅ | ✅ | P0 |
|
||||
| Special | ZeroLengthSection | `ZeroLengthSectionElement` | ✅ | ❌ | P0 |
|
||||
| Special | BeamContact (master/slave) | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 12. Restraints (Boundary Conditions)
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Restraint | Point_Restraints | Node.restraint (6-tuple) | ✅ | ✅ | P0 |
|
||||
| Restraint | Line_Restraints (auto-apply to nodes on line) | — | ❌ | ✅ | P2 |
|
||||
| Restraint | Surface_Restraints (auto-apply to nodes on surface) | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 13. Nodal Loads & Displacements
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Load | Point_Forces | `NodalLoad` | ✅ | ✅ | P0 |
|
||||
| Load | Line_Forces (nodal, along a line) | — | ❌ | ✅ | P2 |
|
||||
| Load | Surface_Forces (nodal, on a surface) | — | ❌ | ✅ | P2 |
|
||||
| Load | Line_Uniform_Forces | `UniformElementLoad` | ✅ | ✅ | P0 |
|
||||
| Load | Point_Displacements (imposed) | — | ❌ | ✅ | P1 |
|
||||
| Load | Line_Displacements (imposed, on nodes along line) | — | ❌ | ✅ | P2 |
|
||||
| Load | Surface_Displacements (imposed, on nodes on surface) | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 14. Ground Motions
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Ground motion | Point_Ground_Motion_from_Record | `PathTimeSeries` + `UniformExcitationPattern` | ✅ | ✅ | P0 |
|
||||
| Ground motion | Point_Sine_Ground_Motion | — (no `TrigTimeSeries`) | ❌ | ✅ | P1 |
|
||||
| Ground motion | Records (BOOK 8 — ground motion file library) | `PathTimeSeries.file_path` (single file, no library) | 🟡 | ✅ | P1 |
|
||||
|
||||
## 15. Constraints
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Constraint | Point_Equal_constraint (master + slave) | `EqualDOFConstraint` | ✅ | ✅ | P0 |
|
||||
| Constraint | Line_Equal_constraint (slave nodes on line) | — | ❌ | ✅ | P1 |
|
||||
| Constraint | Point_Rigid_link (Bar / Beam) | — | ❌ | ✅ | P1 |
|
||||
| Constraint | Line_Rigid_link (slave nodes on line) | — | ❌ | ✅ | P1 |
|
||||
| Constraint | Point_Rigid_diaphragm (master + slave, XY/YZ/ZX plane) | — | ❌ | ✅ | P1 |
|
||||
| Constraint | Line_Rigid_diaphragm (slave nodes on line) | — | ❌ | ✅ | P1 |
|
||||
|
||||
## 16. Mass
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Mass | Point_Mass | node mass (Properties dock + SetMassCommand) | ✅ | ✅ | P0 |
|
||||
| Mass | Line_Mass (auto-lump to nodes) | — | ❌ | ✅ | P1 |
|
||||
| Mass | Surface_Mass | — | ❌ | ✅ | P2 |
|
||||
| Mass | Volume_Mass | — | ❌ | ✅ | P2 |
|
||||
|
||||
## 17. Rayleigh Damping
|
||||
|
||||
| Category | Object (gidopensees) | OTKO name | In OTKO? | In gidopensees? | Priority |
|
||||
|---|---|---|---|---|---|
|
||||
| Damping | Global αM + βK (TransientCase fields) | `TransientCase.rayleigh_alpha_m/beta_k` | ✅ | 🟡 | P0 |
|
||||
| Damping | Mode-1 stiffness-proportional βK auto-compute | `TransientCase.rayleigh_mode1_damping` | ✅ | ❌ | P0 |
|
||||
| Damping | Per-region Rayleigh (Line/Surface/Volume/Point) | — | ❌ | ✅ | P1 |
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Status | Count |
|
||||
|---|---|
|
||||
| ✅ Fully in OTKO | 34 |
|
||||
| 🟡 Partial | 3 |
|
||||
| ❌ P1 targets (Phase 8 additions) | 23 |
|
||||
| ❌ P2 deferred | 21 |
|
||||
|
||||
**Top P1 targets** (highest EQ-engineering impact, not in OTKO yet):
|
||||
|
||||
1. `ElasticPP_with_Gap` — bearing pad / isolation gap nonlinearity
|
||||
2. `Viscous` / `Viscous_Damper` — supplemental damping devices
|
||||
3. `ReinforcingSteel` — DoDD-Restrepo model for well-detailed rebar
|
||||
4. `Concrete04` (Popovics) / `ConcreteCM` (Chang-Mander) — better confined concrete
|
||||
5. `Series` / `Parallel` — material combination building blocks for isolation systems
|
||||
6. `RigidDiaphragm` — floor slab constraint, essential for 3D building models
|
||||
7. `RigidLink` — column/beam offset rigid connections
|
||||
8. `Shell` (MITC4 / ShellDKGQ) — wall / slab elements
|
||||
9. `FiberInt` — P-M interaction section for axial-flexure coupling
|
||||
10. `PointDisplacement` imposed load — displacement-based loading at nodes
|
||||
11. Per-region Rayleigh damping — finer damping control for mixed models
|
||||
12. Sine ground motion / ground motion record library — GM workflow completion
|
||||
46
docs/logo.svg
Normal file
46
docs/logo.svg
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 180" width="720" height="180" role="img" aria-label="OTKO">
|
||||
<title>OTKO</title>
|
||||
<desc>Wordmark logo for OTKO — a SAP2000-style desktop GUI for OpenSeesPy.</desc>
|
||||
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#1F2A3D"/>
|
||||
<stop offset="100%" stop-color="#0F1620"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="frameStroke" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#9DC8FF"/>
|
||||
<stop offset="100%" stop-color="#4F92E8"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="deformed" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stop-color="#4F92E8" stop-opacity="0.0"/>
|
||||
<stop offset="50%" stop-color="#4F92E8" stop-opacity="0.6"/>
|
||||
<stop offset="100%" stop-color="#4F92E8" stop-opacity="0.0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Background panel — keeps contrast consistent on light and dark GitHub themes -->
|
||||
<rect x="0" y="0" width="720" height="180" rx="14" fill="url(#bg)"/>
|
||||
|
||||
<!-- Mark: portal frame with a deformed-shape ghost -->
|
||||
<g transform="translate(40, 36)" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
||||
<path d="M 6 100 C 22 100, 22 12, 60 12 L 60 12 C 98 12, 98 100, 114 100"
|
||||
stroke="url(#deformed)" stroke-width="5" stroke-dasharray="3 5"/>
|
||||
<path d="M 6 100 L 6 8 L 114 8 L 114 100"
|
||||
stroke="url(#frameStroke)" stroke-width="7"/>
|
||||
<rect x="-3" y="100" width="18" height="10" fill="#F2A93B" rx="1"/>
|
||||
<rect x="105" y="100" width="18" height="10" fill="#F2A93B" rx="1"/>
|
||||
<circle cx="6" cy="8" r="5" fill="#E8EDF5"/>
|
||||
<circle cx="114" cy="8" r="5" fill="#E8EDF5"/>
|
||||
</g>
|
||||
|
||||
<!-- Wordmark -->
|
||||
<g font-family="Segoe UI, Inter, Helvetica, Arial, sans-serif">
|
||||
<text x="200" y="92" font-size="56" font-weight="700" letter-spacing="-1">
|
||||
<tspan fill="#E8EDF5">OTKO</tspan>
|
||||
</text>
|
||||
<text x="202" y="124" font-size="16" font-weight="500" letter-spacing="3" fill="#8FA2BF">
|
||||
A SAP2000-STYLE GUI FOR OPENSEESPY
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
197
docs/roadmap.md
Normal file
197
docs/roadmap.md
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
# Roadmap
|
||||
|
||||
Eight phases. 0–7 are the core GUI plus post-processing. Phase 8 is the
|
||||
earthquake-engineering primitives — the part that makes it a research
|
||||
tool instead of a model viewer.
|
||||
|
||||
Status legend: ✅ done · 🟡 partial · ⬜ planned · ✂️ deferred / out-of-scope.
|
||||
|
||||
## Phase 0 — Scaffolding ✅
|
||||
- ✅ Repo, `.gitignore`, `pyproject.toml`
|
||||
- ✅ Pre-commit + ruff + mypy
|
||||
- ✅ GitHub Actions CI (Linux/Mac/Win × Py 3.10–3.12)
|
||||
- ✅ `python -m otko` opens a `MainWindow` with PyVista 3D
|
||||
viewport, model-tree dock, property dock, console dock, working-plane
|
||||
toolbar, and a full menu bar (File / Edit / Define / Assign /
|
||||
Analyze / Display / View / Options / Help)
|
||||
- 🟡 Application icon and About dialog — wordmark logo done; native
|
||||
OS icon (`.ico` / `.icns`) still pending
|
||||
|
||||
## Phase 1 — Core Data Model ✅
|
||||
- ✅ `core.geometry`: `Node`, `Element`, `TrussElement`, `CorotTrussElement`,
|
||||
`ElasticBeamColumn`, `ForceBeamColumn`, `DispBeamColumn`,
|
||||
`ZeroLengthElement`, `ZeroLengthSectionElement`, `BeamWithHingesElement`,
|
||||
`QuadElement`, plus `GridSystem` / `CoordinateSystem`
|
||||
- ✅ `core.materials`: `ElasticIsotropic`, `ElasticUniaxial`, `ElasticPP`,
|
||||
`Steel01`, `Steel02`, `Concrete01`, `Concrete02`, `HystereticMaterial`
|
||||
- ✅ `core.sections`: `ElasticSection`, `FiberSection` with rectangular
|
||||
/ circular patches and straight rebar layers, `SectionAggregator`
|
||||
- ✅ `core.loads`: `NodalLoad`, `UniformElementLoad`, `LinearTimeSeries`,
|
||||
`ConstantTimeSeries`, `PathTimeSeries`, `PlainLoadPattern`,
|
||||
`UniformExcitationPattern`, `ResponseSpectrum`
|
||||
- ✅ `core.analysis`: `StaticCase`, `ModalCase`, `TransientCase`,
|
||||
`PushoverCase`, `ResponseSpectrumCase` — including chained preload
|
||||
via `preload_case_ids` and pattern removal for free-vibration runs
|
||||
- ✅ `core.constraints`: `EqualDOFConstraint` (multi-point constraints)
|
||||
- ✅ `core.project.Project` aggregator with id allocation, validation,
|
||||
`validate_references()`
|
||||
- ✅ `services.persistence`: `.osmodel` (Pydantic JSON) load/save with
|
||||
round-trip-clean assertion in every example script
|
||||
|
||||
## Phase 2 — OpenSees Service ✅
|
||||
- ✅ `services.opensees_runner.OpenSeesRunner` emits commands in the
|
||||
canonical order documented in [`architecture.md`](architecture.md)
|
||||
- ✅ Verified examples (matched analytically or against the OpenSees
|
||||
Wiki Tcl reference): cantilever (point + UDL), portal frame, basic
|
||||
truss, SDOF pushover, RC frame gravity / pushover / earthquake,
|
||||
Examples 1–4 family, two-storey shear / one-bay frames, simply
|
||||
supported beam with quad elements
|
||||
- ✅ `AnalysisWorker(QObject)` runnable inside a `QThread` with
|
||||
`progress(int)` / `log(str)` / `finished(ResultsHandle)` signals
|
||||
|
||||
## Phase 3 — 3D Viewport ✅
|
||||
- ✅ `views.canvas3d.ModelCanvas` (subclass of `QtInteractor` from pyvistaqt)
|
||||
- ✅ Grid plane, world axes triad, view-cube-style preset buttons
|
||||
(Isometric / Top XY / Front XZ / Right YZ), parallel projection toggle
|
||||
- ✅ Node rendering as glyphs; element rendering as tubes (frames /
|
||||
trusses) and shells (quads); supports rendered as gizmos
|
||||
- ✅ Mouse picking → `nodePicked` / `elementPicked` signals; pixel-space
|
||||
grid snap (rejects clicks more than 15 px from an intersection)
|
||||
- ✅ Selection highlighting with in-place colour updates
|
||||
|
||||
## Phase 4 — Modeling Tools ✅
|
||||
- ✅ Grid system dialog (X / Y / Z spacing, generates nodes); SAP2000-style
|
||||
table editor; off-grid clicks rejected
|
||||
- ✅ Working-plane filter — grid + snap restricted to the active level
|
||||
- ✅ Draw Node / Draw Frame / Draw Truss tools with hover snap highlight
|
||||
- ✅ Inline element editing from the Properties dock (truss area,
|
||||
any scalar field)
|
||||
- ✅ Assign Support tool (Free / Pin / Roller / Fix + custom 6-DOF dialog)
|
||||
- ✅ Assign Load: nodal loads, distributed beam loads, ground motions
|
||||
- ✅ Assign EqualDOF (multi-point constraints) from the UI
|
||||
- ✅ Show Extruded Sections toolbar shortcut
|
||||
- ✅ Undo / Redo via `QUndoStack` for every model mutation
|
||||
- 🟡 Replicate / Mirror / Move / Extrude — basic copy works; story-extrude
|
||||
and mirror still pending
|
||||
|
||||
## Phase 5 — Properties ✅
|
||||
- ✅ Material library dialog (CRUD)
|
||||
- ✅ Section library dialog (incl. `FiberSection` rows that previously
|
||||
crashed are now handled)
|
||||
- ✅ Property editor dock — context-aware, multi-selection assignment,
|
||||
inline mass editor
|
||||
- 🟡 Fiber-section visual editor — exists; some UI polish still needed
|
||||
|
||||
## Phase 6 — Analysis Pipeline ✅
|
||||
- ✅ Analysis case manager dialog with case-type factories
|
||||
- ✅ Run dialog with progress + log + cancel
|
||||
- ✅ Per-run Rayleigh damping override (no project mutation)
|
||||
- ✅ Results stored to `<project>.osresults.h5`
|
||||
- 🟡 Convergence diagnostics view (residuals per step) — partial info
|
||||
in run log; dedicated diagnostics dock pending
|
||||
|
||||
## Phase 7 — Post-processing ✅
|
||||
- ✅ Deformed shape with scale-factor slider
|
||||
- ✅ Mode-shape animator (1-indexed; play / scrub / scale)
|
||||
- ✅ Element force diagrams (axial, shear, moment) with auto-pick of
|
||||
the largest-magnitude component on dock open, numerical labels at
|
||||
global min/max ends
|
||||
- ✅ Time-history plotter (pyqtgraph) with displacement / velocity /
|
||||
acceleration switching
|
||||
- ✅ Hysteresis plotter — node DOF orbits and element local-force loops
|
||||
- ✅ Pushover curve view in display units
|
||||
- ✅ Response-spectrum view (Sa-T curve with modal-period markers and a
|
||||
mass-participation table)
|
||||
- ✅ Snapshot / video export (mode shapes + time histories) via
|
||||
`imageio[ffmpeg]`
|
||||
- ⬜ **Render performance pass** — collapse per-entity actors into glyphed
|
||||
PolyData (single draw call), in-place colour updates for selection,
|
||||
AA, lower-tessellation spheres. Target: 10k nodes / 20k frames @ 30 fps
|
||||
|
||||
## Phase 8 — Earthquake Engineering 🟡
|
||||
- ✅ `HystereticMaterial`, `BeamWithHinges`, `FiberSection` → all
|
||||
flowing into the runner, end-to-end pushover example
|
||||
- ✅ Response spectrum generator + SRSS / CQC modal combination
|
||||
- ✅ Ground-motion import via `PathTimeSeries` + `UniformExcitationPattern`,
|
||||
with an example wired up against the OpenSees A10000 record
|
||||
- ✅ `ZeroLengthSectionElement` for moment-curvature workflows; closed-form
|
||||
verification example shipped
|
||||
- ✅ `Concrete04` (Popovics) end-to-end: model → runner → UI form → tests →
|
||||
fiber-section cantilever example
|
||||
- ✅ **Material Tester service** (`services/material_tester.py`) — headless,
|
||||
Qt-free; runs any uniaxial material through a monotonic or cyclic strain
|
||||
protocol in an isolated single-element model and returns the full
|
||||
stress–strain history. Verified: Elastic linearity, ElasticPP plateau,
|
||||
Steel01 hysteresis energy (EPP formula, <1%), Concrete04 Popovics C1
|
||||
continuity; state-cleanup and interleave proofs.
|
||||
- ⬜ **Material Tester dialog** — Qt front-end for the service above; live
|
||||
stress–strain plot with strain-amplitude and step controls
|
||||
- ⬜ Seismic isolators: `elastomericBearing*`, `frictionPendulumBearing`,
|
||||
`singleFPBearing`, `TripleFrictionPendulum`
|
||||
- ⬜ Ground-motion library (PEER-style record set + scaling tools)
|
||||
- ⬜ IDA (Incremental Dynamic Analysis) batch runner
|
||||
- 🟡 Fiber-section editor — exists for rectangular / circular sections;
|
||||
confined / unconfined visual presets pending
|
||||
|
||||
## Out-of-scope (for now)
|
||||
- ✂️ Code-checking (TBDY-2018, ASCE 41, Eurocode 8)
|
||||
- ✂️ Soil-structure interaction GUI
|
||||
- ✂️ Cloud / collaborative editing
|
||||
- ✂️ Native shell-element rendering / pre-processing (quads exist as a
|
||||
primitive, but a proper shell workflow is its own phase)
|
||||
|
||||
## Next sessions — backlog (Sept 2026 cooldown session)
|
||||
|
||||
Session handoff first: ~60 files of uncommitted work in the tree
|
||||
(Table dock, extrusion shapes, exporter, pattern_factors, all audit
|
||||
fixes). Commit per Conventional Commits on `develop` before new work
|
||||
(`feat:`/`fix:` split per lane), then `ruff check src tests &&
|
||||
ruff format src tests`, `mypy`, `pytest -m "not slow"`.
|
||||
|
||||
Requested (user-ordered):
|
||||
|
||||
1. ⬜ Toolbar button icons — `resources/icons/` exists; wire `QIcon`s
|
||||
in `menu_builder.py` toolbar builders (`@designer` lane: layout,
|
||||
hierarchy, affordances). Include OS icon (`.ico`/`.icns`, Phase 0 🟡).
|
||||
2. ⬜ Shell objects — analysis first: `QuadElement` today is continuum
|
||||
(plane stress/strain). Scope OpenSees `ShellMITC4`/`ShellDKGQ` +
|
||||
shell sections/materials, then core element + `_emit` + renderer
|
||||
quad→shell + section dialog. Keep solver-source untouched
|
||||
(emit `-factor`-style floats only). (`@oracle` for the scope call.)
|
||||
3. ⬜ Input-dialog layout/usability pass — continue the Lane C pattern:
|
||||
`QFormLayout` consistency, prefill from selection (done for assign
|
||||
dialogs), inline validation messages instead of silent reverts,
|
||||
units-aware labels. (`@designer` for layout, orchestrator for copy.)
|
||||
4. ⬜ Hover tooltips — two halves: (a) canvas entity hover (node/element
|
||||
id + key values via existing picking signals); (b) widget tooltip
|
||||
audit (every toolbar button/dialog field documents itself).
|
||||
5. ⬜ Load visibility filter — show only loads of the selected pattern /
|
||||
case; hide the rest. Renderer load-overlay filter + selector combo
|
||||
(builds on the Table Loads tabs' pattern filter). Natural home:
|
||||
View toolbar next to Show Local Axes.
|
||||
|
||||
Identified this session (audit + build leftovers):
|
||||
|
||||
6. ⬜ Named load combinations (deferred phase 3) — `pattern_factors`
|
||||
covers per-case factoring; add a reusable named-combo entity only
|
||||
if one combo must be shared across many cases.
|
||||
7. ⬜ Per-row Run + status in Table Analyses tab — run control lives
|
||||
only in the Run dialog today; add per-case Run button + last-run
|
||||
status (converged/failed/when). No overlap: the tab lists cases,
|
||||
this operates them.
|
||||
8. ⬜ Case-manager edit preservation — `modelMutated` while the manager
|
||||
is open rebuilds the form and discards in-progress edits (audit C2).
|
||||
9. ⬜ Table dock phase-4 polish — CSV copy/paste, column visibility
|
||||
(deferred from the Table plan).
|
||||
10. ⬜ Display-settings persistence — extruded-sections / local-axes /
|
||||
parallel-projection toggles reset per project; persist viewport
|
||||
prefs in `QSettings` (no `DisplaySettings` module exists yet).
|
||||
11. ⬜ GUI test coverage under xvfb — `views/*` omitted from coverage;
|
||||
lanes verified via offscreen smoke only. Add pytest-qt tests for:
|
||||
dock toggles, Level refresh, post-state teardown, Table edits,
|
||||
factor spins, local-axes overlay.
|
||||
12. ⬜ Pin ruff version — local ruff (0.15.x) flags pre-existing drift
|
||||
(UP037/RUF001/RUF003/E702) that repo CI doesn't; pin in
|
||||
`pyproject.toml` or baseline-allowlist so `ruff check` is green.
|
||||
13. ⬜ Exported-Tcl round trip — `.py` export is solver-verified;
|
||||
add an equivalent exec-and-compare test for the `.tcl` renderer.
|
||||
BIN
docs/screenshots/main_window.png
Normal file
BIN
docs/screenshots/main_window.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 505 KiB |
0
examples/.gitkeep
Normal file
0
examples/.gitkeep
Normal file
227
examples/README.md
Normal file
227
examples/README.md
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# Example models
|
||||
|
||||
Pre-built `.osmodel` files plus the Python scripts that generate them.
|
||||
Each one carries the case types the post-processing views need, so you
|
||||
can exercise the GUI without defining materials, sections, loads, and
|
||||
cases by hand.
|
||||
|
||||
## Files
|
||||
|
||||
| Model | Nodes | Elements | Cases | Shows |
|
||||
|---|---|---|---|---|
|
||||
| `cantilever.osmodel` | 6 | 5 | Static × 2, Modal | Point + distributed loads, force diagrams, deformed shape, mode shapes |
|
||||
| `portal_frame.osmodel` | 4 | 3 | Static, Modal, Transient | All Display features, smallest 3D |
|
||||
| `space_frame_3d.osmodel` | 12 | 16 | Static, Modal, Transient (5% damping) | 3D rendering, multiple modes, damped EQ time-history |
|
||||
| `sdof_pushover.osmodel` | 2 | 1 | Pushover, Modal | Monotonic pushover curve, HystereticMaterial |
|
||||
| `portal_pushover.osmodel` | 4 | 3 | Pushover, Modal | Fiber sections, BeamWithHinges, yielding pushover |
|
||||
| `ex1a_canti2d.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | OpenSees Ex 1a, shared gravity + push + quake |
|
||||
| `ex1b_portal2d.osmodel` | 4 | 3 | Static preload, Pushover, Transient EQ | OpenSees Ex 1b elastic portal, distributed gravity |
|
||||
| `ex2a_canti2d_elastic_element.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | Ex 2a cantilever, dimensions as named parameters |
|
||||
| `ex2b_canti2d_inelastic_section.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | Ex 2b, aggregated axial+flexure section |
|
||||
| `ex2c_canti2d_inelastic_fiber_section.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | Ex 2c, fiber section, coupled axial-flexure |
|
||||
| `ex3_canti2d_elastic_element.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | Ex 3 elastic build, unit-scaled parameters |
|
||||
| `ex3_canti2d_inelastic_section.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | Ex 3 aggregated-section build |
|
||||
| `ex3_canti2d_inelastic_fiber_section.osmodel` | 2 | 1 | Static preload, Pushover, Transient EQ | Ex 3 fiber-section build |
|
||||
| `ex4_portal2d_elastic_element.osmodel` | 4 | 3 | Static preload, Pushover, Transient sine | Ex 4 elastic portal, build/analysis split |
|
||||
| `ex4_portal2d_inelastic_section.osmodel` | 4 | 3 | Static preload, Pushover, Transient sine | Ex 4 aggregated-section portal |
|
||||
| `ex4_portal2d_inelastic_fiber_section.osmodel` | 4 | 3 | Static preload, Pushover, Transient sine | Ex 4 fiber-section portal |
|
||||
| `ex1a_canti2d_eq.osmodel` | 2 | 1 | Static preload, Transient EQ | Ex 1a gravity + base excitation only |
|
||||
| `eigen_two_storey_shear_frame.osmodel` | 6 | 6 | Modal | equalDOF floor constraints, shear-frame modes |
|
||||
| `eigen_two_storey_one_bay_frame.osmodel` | 6 | 6 | Modal | Chopra 10.5 frame, sway modes, no constraints |
|
||||
| `concrete04_cantilever.osmodel` | 2 | 1 | Static (gravity), Pushover | Concrete04 fiber section end-to-end |
|
||||
|
||||
## Quick tour
|
||||
|
||||
### 1. Force diagrams — `cantilever.osmodel`
|
||||
```
|
||||
File → Open → cantilever.osmodel
|
||||
Analyze → Cases → run "Tip-Load"
|
||||
Display → Show Force Diagram → component "M3" → linear moment, max at fixed end (50 kN·m)
|
||||
→ component "V2" → constant -10 kN along the whole span
|
||||
→ component "N" → ~zero (no axial load)
|
||||
→ component "T" → ~zero (no torsion → console hint, no diagram)
|
||||
Display → Show Deformed Shape → cantilever curve
|
||||
```
|
||||
Load runs along global Y (perpendicular to the beam, horizontal plane).
|
||||
With the default 3D vertical-reference convention that lands on the
|
||||
V2 / M3 pair — the in-plane bending pair.
|
||||
|
||||
UDL variant, parabolic moment:
|
||||
```
|
||||
Analyze → Cases → run "Uniform-Load"
|
||||
Display → Show Force Diagram → M3 → parabolic, max 25 kN·m at fixed end
|
||||
→ V2 → linear, max 10 kN at fixed end
|
||||
```
|
||||
|
||||
### 2. Mode shapes — `space_frame_3d.osmodel`
|
||||
```
|
||||
File → Open → space_frame_3d.osmodel
|
||||
Analyze → Cases → run "Modal-6"
|
||||
Display → Animate Mode Shape → mode 1 = X-sway, mode 2 = Y-sway
|
||||
→ Play, scrub timeline, change scale
|
||||
```
|
||||
|
||||
### 3. Time-history and hysteresis — `space_frame_3d.osmodel`
|
||||
```
|
||||
File → Open → space_frame_3d.osmodel
|
||||
Analyze → Cases → run "EQ-4s" (~5-10 sec on a modern laptop)
|
||||
Display → Time-History Plot
|
||||
- Node 12 (roof corner) + DOF 1 (X displacement) → "Add trace"
|
||||
- Node 9 + DOF 1 → second trace, compare phase
|
||||
Display → Hysteresis Plot
|
||||
- X = Node 12 / DOF 1, Y = Node 12 / DOF 3 → orbit
|
||||
```
|
||||
|
||||
### 4. Pushover — `sdof_pushover.osmodel`
|
||||
```
|
||||
File → Open → sdof_pushover.osmodel
|
||||
Analyze → Cases → run "Push-X"
|
||||
Display → Show Pushover Curve
|
||||
→ linear from origin, then softens through yield
|
||||
```
|
||||
Column stays elastic here. Real nonlinear hinges need
|
||||
BeamWithHinges + fiber sections; the machinery exists, the
|
||||
fiber-section editor is still rough.
|
||||
|
||||
### 5. Nonlinear pushover with fiber hinges — `portal_pushover.osmodel`
|
||||
```
|
||||
File → Open → portal_pushover.osmodel
|
||||
Analyze → Cases → run "Push-X"
|
||||
Display → Show Pushover Curve
|
||||
→ linear stiffness, then yield plateau as base hinges form
|
||||
→ peak base shear = concrete crushing + rebar yield
|
||||
```
|
||||
Columns are BeamWithHinges + FiberSections (concrete core, rebar
|
||||
layers) wrapped in a SectionAggregator for torsion.
|
||||
|
||||
### 6. Gravity + time-history chain — `ex1a_canti2d_eq.osmodel`
|
||||
```
|
||||
File → Open → ex1a_canti2d_eq.osmodel
|
||||
Analyze → Cases → run "Earthquake"
|
||||
Display → Time-History Plot
|
||||
- Node 2 + DOF 1 (Ux) → tip horizontal response
|
||||
- Node 2 + DOF 2 (Uy) → gravity should stay locked
|
||||
```
|
||||
Tiny model, exists for one reason: the standard transient recipe
|
||||
`static preload → loadConst reset → UniformExcitation transient`
|
||||
against a real ground-motion record in a `PathTimeSeries`.
|
||||
|
||||
### 7. OpenSees Ex 1a bundle — `ex1a_canti2d.osmodel`
|
||||
```
|
||||
File → Open → ex1a_canti2d.osmodel
|
||||
Analyze → Cases → run "Push" or "Earthquake"
|
||||
Display → Show Pushover Curve / Time-History Plot
|
||||
```
|
||||
Cantilever column with shared gravity preload and both lateral
|
||||
variants. Small benchmark for checking pushover and transient agree
|
||||
on the same geometry.
|
||||
|
||||
### 8. OpenSees Ex 1b bundle — `ex1b_portal2d.osmodel`
|
||||
```
|
||||
File → Open → ex1b_portal2d.osmodel
|
||||
Analyze → Cases → run "Push" or "Earthquake"
|
||||
Display → Show Pushover Curve / Time-History Plot
|
||||
```
|
||||
Elastic portal frame. Gravity comes from a distributed beam load
|
||||
instead of nodal loads, which is the whole point of keeping it
|
||||
around.
|
||||
|
||||
### 9. Ex 2a, parameter-driven — `ex2a_canti2d_elastic_element.osmodel`
|
||||
```
|
||||
File → Open → ex2a_canti2d_elastic_element.osmodel
|
||||
Analyze → Cases → run "Push" or "Earthquake"
|
||||
Display → Show Pushover Curve / Time-History Plot
|
||||
```
|
||||
Same physics as Ex 1a, but dimensions and derived quantities are
|
||||
named parameters instead of literals.
|
||||
|
||||
### 10. Ex 2b, aggregated section — `ex2b_canti2d_inelastic_section.osmodel`
|
||||
```
|
||||
File → Open → ex2b_canti2d_inelastic_section.osmodel
|
||||
Analyze → Cases → run "Push" or "Earthquake"
|
||||
Display → Show Pushover Curve / Time-History Plot
|
||||
```
|
||||
First nonlinear cantilever in the series. Separate axial and flexural
|
||||
uniaxial responses aggregated into one section on a force-based
|
||||
beam-column.
|
||||
|
||||
### 11. Ex 2c, fiber section — `ex2c_canti2d_inelastic_fiber_section.osmodel`
|
||||
```
|
||||
File → Open → ex2c_canti2d_inelastic_fiber_section.osmodel
|
||||
Analyze → Cases → run "Push" or "Earthquake"
|
||||
Display → Show Pushover Curve / Time-History Plot
|
||||
```
|
||||
Ex 2b's fiber counterpart. Coupled axial-flexure with concrete and
|
||||
steel assigned to fibers and rebar layers directly.
|
||||
|
||||
### 12. Ex 3 family — `ex3_canti2d_*.osmodel`
|
||||
```
|
||||
File → Open → ex3_canti2d_elastic_element.osmodel
|
||||
Analyze → Cases → run "Push" or "Earthquake"
|
||||
```
|
||||
Same cantilever analyses on three build styles: elastic element,
|
||||
aggregated uniaxial section, fiber section. All unit-scaled.
|
||||
|
||||
### 13. Modal shear building — `eigen_two_storey_shear_frame.osmodel`
|
||||
```
|
||||
File → Open → eigen_two_storey_shear_frame.osmodel
|
||||
Analyze → Cases → run "Modal-2"
|
||||
Display → Animate Mode Shape
|
||||
- mode 1 → stories sway in phase
|
||||
- mode 2 → stories sway out of phase
|
||||
```
|
||||
Validates modal workflows on a model small enough to check by hand,
|
||||
with `equalDOF` doing the shear-frame duty.
|
||||
|
||||
### 14. Modal frame, Chopra 10.5 — `eigen_two_storey_one_bay_frame.osmodel`
|
||||
```
|
||||
File → Open → eigen_two_storey_one_bay_frame.osmodel
|
||||
Analyze → Cases → run "Modal-2"
|
||||
Display → Animate Mode Shape
|
||||
- mode 1 → in-phase sway of both stories
|
||||
- mode 2 → top story reverses against the first
|
||||
```
|
||||
Companion to the shear building above. Ordinary beam-column behavior,
|
||||
no multi-point constraints.
|
||||
|
||||
### 15. Ex 4 portal family — `ex4_portal2d_*.osmodel`
|
||||
```
|
||||
File → Open → ex4_portal2d_elastic_element.osmodel
|
||||
Analyze → Cases → run "Push" or "Sine-Uniform"
|
||||
Display → Show Pushover Curve / Time-History Plot
|
||||
```
|
||||
Keeps the OpenSees split between model-building and analysis files,
|
||||
recast as project variants. Covers pinned-base sway, distributed
|
||||
girder gravity, and support-motion dynamics without an external quake
|
||||
file. The fiber transient is kept as a nonlinear stress test — it may
|
||||
stop early and still produce usable partial histories.
|
||||
|
||||
## Regenerating the .osmodel files
|
||||
|
||||
Scripts are the source of truth, `.osmodel` files are build artifacts
|
||||
checked in for convenience. Change a script, rerun it:
|
||||
|
||||
```bash
|
||||
python examples/cantilever.py
|
||||
python examples/portal_frame.py
|
||||
python examples/space_frame_3d.py
|
||||
python examples/sdof_pushover.py
|
||||
python examples/portal_pushover.py
|
||||
python examples/ex1a_canti2d.py
|
||||
python examples/ex1b_portal2d.py
|
||||
python examples/ex2a_canti2d_elastic_element.py
|
||||
python examples/ex1a_canti2d_eq.py
|
||||
python examples/ex2b_canti2d_inelastic_section.py
|
||||
python examples/ex2c_canti2d_inelastic_fiber_section.py
|
||||
python examples/ex3_canti2d_elastic_element.py
|
||||
python examples/ex3_canti2d_inelastic_section.py
|
||||
python examples/ex3_canti2d_inelastic_fiber_section.py
|
||||
python examples/ex4_portal2d_elastic_element.py
|
||||
python examples/ex4_portal2d_inelastic_section.py
|
||||
python examples/ex4_portal2d_inelastic_fiber_section.py
|
||||
python examples/eigen_two_storey_shear_frame.py
|
||||
python examples/eigen_two_storey_one_bay_frame.py
|
||||
```
|
||||
|
||||
Each script builds the project, saves it, reloads it, and asserts a
|
||||
clean round-trip.
|
||||
460
examples/_ex4_portal2d_common.py
Normal file
460
examples/_ex4_portal2d_common.py
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
"""Shared builders for OpenSees Example 4 portal-frame variants."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
AggregatorDOF,
|
||||
Concrete02,
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
ElasticUniaxial,
|
||||
FiberSection,
|
||||
ForceBeamColumn,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
RectangularPatch,
|
||||
SectionAggregator,
|
||||
StaticCase,
|
||||
Steel01,
|
||||
Steel02,
|
||||
StraightLayer,
|
||||
TransientCase,
|
||||
UniformElementLoad,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
|
||||
|
||||
INCH = 1.0
|
||||
KIP = 1.0
|
||||
SEC = 1.0
|
||||
FT = 12.0 * INCH
|
||||
KSI = KIP / INCH**2
|
||||
PSI = KSI / 1000.0
|
||||
G_ACCEL = 32.2 * FT / SEC**2
|
||||
PI = math.pi
|
||||
|
||||
L_COL = 36.0 * FT
|
||||
L_BEAM = 42.0 * FT
|
||||
H_BEAM = 8.0 * FT
|
||||
B_BEAM = 5.0 * FT
|
||||
A_BEAM = B_BEAM * H_BEAM
|
||||
IZ_BEAM = (1.0 / 12.0) * B_BEAM * H_BEAM**3
|
||||
|
||||
FC = -4.0 * KSI
|
||||
E_C = 57.0 * KSI * math.sqrt(-FC / PSI)
|
||||
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
PUSH_TARGET = 0.1 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
NUM_INT_PTS = 5
|
||||
|
||||
SINE_AMPLITUDE = 0.5 * G_ACCEL
|
||||
SINE_PERIOD = 0.35 * SEC
|
||||
SINE_DURATION = 3.0 * SEC
|
||||
GROUND_DT = 0.005 * SEC
|
||||
ANALYSIS_DT = 0.01 * SEC
|
||||
ANALYSIS_DURATION = 10.0 * SEC
|
||||
ANALYSIS_STEPS = int(ANALYSIS_DURATION / ANALYSIS_DT)
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex4.Portal2D.analyze.Static.Push.tcl.txt"
|
||||
REFERENCE_SINE_TCL = _ROOT / "data" / "Ex4.Portal2D.analyze.Dynamic.sine.Uniform.tcl.txt"
|
||||
|
||||
|
||||
def sine_accel_values(
|
||||
dt: float = GROUND_DT,
|
||||
amplitude: float = SINE_AMPLITUDE,
|
||||
period: float = SINE_PERIOD,
|
||||
duration: float = SINE_DURATION,
|
||||
) -> list[float]:
|
||||
"""Sample the Example 4 sine support motion as a PathTimeSeries."""
|
||||
|
||||
omega = 2.0 * PI / period
|
||||
n_points = int(round(duration / dt)) + 1
|
||||
return [amplitude * math.sin(omega * i * dt) for i in range(n_points)]
|
||||
|
||||
|
||||
def sine_velocity_values(
|
||||
dt: float = GROUND_DT,
|
||||
amplitude: float = SINE_AMPLITUDE,
|
||||
period: float = SINE_PERIOD,
|
||||
duration: float = SINE_DURATION,
|
||||
) -> list[float]:
|
||||
"""Velocity history consistent with the Tcl ``-vel0`` sine recipe."""
|
||||
|
||||
omega = 2.0 * PI / period
|
||||
n_points = int(round(duration / dt)) + 1
|
||||
return [-(amplitude / omega) * math.cos(omega * i * dt) for i in range(n_points)]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ElasticVariant:
|
||||
name: str
|
||||
description: str
|
||||
weight: float
|
||||
h_col: float
|
||||
b_col: float
|
||||
build_tcl_name: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class InelasticSectionVariant(ElasticVariant):
|
||||
my_col: float
|
||||
phi_y_col: float
|
||||
hardening_ratio: float = 0.01
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FiberVariant(ElasticVariant):
|
||||
cover_col: float
|
||||
num_bars_col: int
|
||||
bar_area_col: float
|
||||
eps1_u: float
|
||||
eps2_u: float
|
||||
lambda_: float
|
||||
fy: float
|
||||
es: float
|
||||
bs: float
|
||||
r0: float
|
||||
cr1: float
|
||||
cr2: float
|
||||
n_fib_y: int
|
||||
n_fib_z: int
|
||||
|
||||
|
||||
ELASTIC_VARIANT = ElasticVariant(
|
||||
name="OpenSees Ex 4 - Portal Frame (Elastic Build)",
|
||||
description="Example 4 elastic portal frame with shared gravity, push, and sine-wave support motion.",
|
||||
weight=4000.0 * KIP,
|
||||
h_col=5.0 * FT,
|
||||
b_col=4.0 * FT,
|
||||
build_tcl_name="Ex4.Portal2D.build.ElasticElement.tcl.txt",
|
||||
)
|
||||
|
||||
INELASTIC_SECTION_VARIANT = InelasticSectionVariant(
|
||||
name="OpenSees Ex 4 - Portal Frame (Inelastic Section Build)",
|
||||
description="Example 4 portal frame with aggregated uniaxial inelastic column sections and shared analyses.",
|
||||
weight=4000.0 * KIP,
|
||||
h_col=5.0 * FT,
|
||||
b_col=4.0 * FT,
|
||||
build_tcl_name="Ex4.Portal2D.build.InelasticSection.tcl.txt",
|
||||
my_col=130000.0 * KIP * INCH,
|
||||
phi_y_col=0.65e-4 / INCH,
|
||||
)
|
||||
|
||||
FIBER_VARIANT = FiberVariant(
|
||||
name="OpenSees Ex 4 - Portal Frame (Fiber Section Build)",
|
||||
description="Example 4 portal frame with fiber-section columns and shared pushover / sine-wave analyses.",
|
||||
weight=2000.0 * KIP,
|
||||
h_col=5.0 * FT,
|
||||
b_col=5.0 * FT,
|
||||
build_tcl_name="Ex4.Portal2D.build.InelasticFiberSection.tcl.txt",
|
||||
cover_col=6.0 * INCH,
|
||||
num_bars_col=10,
|
||||
bar_area_col=2.25 * INCH**2,
|
||||
eps1_u=-0.003,
|
||||
eps2_u=-0.05,
|
||||
lambda_=0.1,
|
||||
fy=66.8 * KSI,
|
||||
es=29000.0 * KSI,
|
||||
bs=0.01,
|
||||
r0=18.0,
|
||||
cr1=0.925,
|
||||
cr2=0.15,
|
||||
n_fib_y=16,
|
||||
n_fib_z=4,
|
||||
)
|
||||
|
||||
|
||||
def _common_nodes(weight: float) -> list[Node]:
|
||||
p_col = weight / 2.0
|
||||
mass = p_col / G_ACCEL
|
||||
return [
|
||||
Node(id=1, name="Base-L", coords=(0.0, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="Base-R", coords=(L_BEAM, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=3, name="Top-L", coords=(0.0, L_COL, 0.0), mass=(mass, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=4, name="Top-R", coords=(L_BEAM, L_COL, 0.0), mass=(mass, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
]
|
||||
|
||||
|
||||
def _common_patterns(weight: float) -> tuple[list[LinearTimeSeries | PathTimeSeries], list[PlainLoadPattern | UniformExcitationPattern]]:
|
||||
p_col = weight / 2.0
|
||||
w_beam = -weight / L_BEAM
|
||||
time_series = [
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=200, name="Lateral"),
|
||||
PathTimeSeries(
|
||||
id=400,
|
||||
name="Sine-0p5g",
|
||||
dt=GROUND_DT,
|
||||
values=sine_accel_values(),
|
||||
file_path="generated:sine-wave",
|
||||
),
|
||||
PathTimeSeries(
|
||||
id=401,
|
||||
name="SineVel-0p5g",
|
||||
dt=GROUND_DT,
|
||||
values=sine_velocity_values(),
|
||||
file_path="generated:sine-wave-velocity",
|
||||
),
|
||||
]
|
||||
patterns = [
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
element_loads=[UniformElementLoad(element_id=3, wy=w_beam)],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=200,
|
||||
name="Pushover-X",
|
||||
time_series_id=200,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=3, forces=(p_col, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
NodalLoad(node_id=4, forces=(p_col, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=400,
|
||||
name="Sine-Uniform-X",
|
||||
direction=1,
|
||||
accel_series_id=400,
|
||||
vel_series_id=401,
|
||||
),
|
||||
]
|
||||
return time_series, patterns
|
||||
|
||||
|
||||
def _common_analyses() -> list[StaticCase | PushoverCase | TransientCase]:
|
||||
return [
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=N_GRAVITY,
|
||||
load_factor_increment=GRAVITY_STEP,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2,
|
||||
name="Push",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[200],
|
||||
control_node=3,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1, 2],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
TransientCase(
|
||||
id=3,
|
||||
name="Sine-Uniform",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[400],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=ANALYSIS_STEPS,
|
||||
system="BandGeneral",
|
||||
constraints="Transformation",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="ModifiedNewton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def build_ex4_portal2d_elastic_element() -> Project:
|
||||
a_col = ELASTIC_VARIANT.b_col * ELASTIC_VARIANT.h_col
|
||||
iz_col = (1.0 / 12.0) * ELASTIC_VARIANT.b_col * ELASTIC_VARIANT.h_col**3
|
||||
time_series, patterns = _common_patterns(ELASTIC_VARIANT.weight)
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name=ELASTIC_VARIANT.name,
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=ELASTIC_VARIANT.description,
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=_common_nodes(ELASTIC_VARIANT.weight),
|
||||
sections=[
|
||||
ElasticSection(id=1, name="Columns", E=E_C, A=a_col, Iz=iz_col, Iy=iz_col, G=1.0, J=1.0),
|
||||
ElasticSection(id=2, name="Beam", E=E_C, A=A_BEAM, Iz=IZ_BEAM, Iy=IZ_BEAM, G=1.0, J=1.0),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(id=1, name="Col-L", nodes=(1, 3), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=2, name="Col-R", nodes=(2, 4), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=3, name="Beam", nodes=(3, 4), section_id=2, geom_transf="Linear"),
|
||||
],
|
||||
time_series=time_series,
|
||||
load_patterns=patterns,
|
||||
analyses=_common_analyses(),
|
||||
)
|
||||
|
||||
|
||||
def build_ex4_portal2d_inelastic_section() -> Project:
|
||||
a_col = INELASTIC_SECTION_VARIANT.b_col * INELASTIC_SECTION_VARIANT.h_col
|
||||
ei_col_cracked = INELASTIC_SECTION_VARIANT.my_col / INELASTIC_SECTION_VARIANT.phi_y_col
|
||||
time_series, patterns = _common_patterns(INELASTIC_SECTION_VARIANT.weight)
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name=INELASTIC_SECTION_VARIANT.name,
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=INELASTIC_SECTION_VARIANT.description,
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=_common_nodes(INELASTIC_SECTION_VARIANT.weight),
|
||||
materials=[
|
||||
Steel01(
|
||||
id=2,
|
||||
name="Flexural-Steel01",
|
||||
Fy=INELASTIC_SECTION_VARIANT.my_col,
|
||||
E0=ei_col_cracked,
|
||||
b=INELASTIC_SECTION_VARIANT.hardening_ratio,
|
||||
),
|
||||
ElasticUniaxial(id=3, name="Axial-Elastic", E=E_C * a_col),
|
||||
],
|
||||
sections=[
|
||||
SectionAggregator(
|
||||
id=1,
|
||||
name="Column-Section",
|
||||
pairings=[
|
||||
AggregatorDOF(material_id=3, dof="P"),
|
||||
AggregatorDOF(material_id=2, dof="Mz"),
|
||||
],
|
||||
),
|
||||
ElasticSection(id=2, name="Beam", E=E_C, A=A_BEAM, Iz=IZ_BEAM, Iy=IZ_BEAM, G=1.0, J=1.0),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(id=1, name="Col-L", nodes=(1, 3), section_id=1, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
ForceBeamColumn(id=2, name="Col-R", nodes=(2, 4), section_id=1, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
ForceBeamColumn(id=3, name="Beam", nodes=(3, 4), section_id=2, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
],
|
||||
time_series=time_series,
|
||||
load_patterns=patterns,
|
||||
analyses=_common_analyses(),
|
||||
)
|
||||
|
||||
|
||||
def build_ex4_portal2d_inelastic_fiber_section() -> Project:
|
||||
cover_y = FIBER_VARIANT.h_col / 2.0
|
||||
cover_z = FIBER_VARIANT.b_col / 2.0
|
||||
core_y = cover_y - FIBER_VARIANT.cover_col
|
||||
core_z = cover_z - FIBER_VARIANT.cover_col
|
||||
ft_u = -0.14 * FC
|
||||
ets = ft_u / 0.002
|
||||
time_series, patterns = _common_patterns(FIBER_VARIANT.weight)
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name=FIBER_VARIANT.name,
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=FIBER_VARIANT.description,
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=_common_nodes(FIBER_VARIANT.weight),
|
||||
materials=[
|
||||
Concrete02(
|
||||
id=1,
|
||||
name="Cover-Concrete",
|
||||
fpc=FC,
|
||||
epsc0=FIBER_VARIANT.eps1_u,
|
||||
fpcu=0.2 * FC,
|
||||
epsU=FIBER_VARIANT.eps2_u,
|
||||
lambda_=FIBER_VARIANT.lambda_,
|
||||
ft=ft_u,
|
||||
Ets=ets,
|
||||
),
|
||||
Steel02(
|
||||
id=2,
|
||||
name="Rebar-Steel02",
|
||||
Fy=FIBER_VARIANT.fy,
|
||||
E0=FIBER_VARIANT.es,
|
||||
b=FIBER_VARIANT.bs,
|
||||
R0=FIBER_VARIANT.r0,
|
||||
cR1=FIBER_VARIANT.cr1,
|
||||
cR2=FIBER_VARIANT.cr2,
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
FiberSection(
|
||||
id=1,
|
||||
name="Column-Fiber-Section",
|
||||
patches=[
|
||||
RectangularPatch(
|
||||
material_id=1,
|
||||
n_fib_y=FIBER_VARIANT.n_fib_y,
|
||||
n_fib_z=FIBER_VARIANT.n_fib_z,
|
||||
y_i=-cover_y,
|
||||
z_i=-cover_z,
|
||||
y_j=cover_y,
|
||||
z_j=cover_z,
|
||||
),
|
||||
],
|
||||
layers=[
|
||||
StraightLayer(
|
||||
material_id=2,
|
||||
n_bars=FIBER_VARIANT.num_bars_col,
|
||||
bar_area=FIBER_VARIANT.bar_area_col,
|
||||
y_start=-core_y,
|
||||
z_start=core_z,
|
||||
y_end=-core_y,
|
||||
z_end=-core_z,
|
||||
),
|
||||
StraightLayer(
|
||||
material_id=2,
|
||||
n_bars=FIBER_VARIANT.num_bars_col,
|
||||
bar_area=FIBER_VARIANT.bar_area_col,
|
||||
y_start=core_y,
|
||||
z_start=core_z,
|
||||
y_end=core_y,
|
||||
z_end=-core_z,
|
||||
),
|
||||
],
|
||||
),
|
||||
ElasticSection(id=2, name="Beam", E=E_C, A=A_BEAM, Iz=IZ_BEAM, Iy=IZ_BEAM, G=1.0, J=1.0),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(id=1, name="Col-L", nodes=(1, 3), section_id=1, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
ForceBeamColumn(id=2, name="Col-R", nodes=(2, 4), section_id=1, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
ForceBeamColumn(id=3, name="Beam", nodes=(3, 4), section_id=2, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
],
|
||||
time_series=time_series,
|
||||
load_patterns=patterns,
|
||||
analyses=_common_analyses(),
|
||||
)
|
||||
298
examples/basic_truss.osmodel
Normal file
298
examples/basic_truss.osmodel
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Basic Truss",
|
||||
"description": "3-bar asymmetric planar truss, linear static analysis.",
|
||||
"author": "OpenSees Examples Manual - Example 1",
|
||||
"units": "SI (m, N, kg, s, Pa)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 2,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [
|
||||
{
|
||||
"id": "X1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X2",
|
||||
"ordinate": 1.8288,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X3",
|
||||
"ordinate": 3.6576,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X4",
|
||||
"ordinate": 4.2672,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"y_grid_lines": [
|
||||
{
|
||||
"id": "Y1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y2",
|
||||
"ordinate": 2.4383999999999997,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"z_grid_lines": [
|
||||
{
|
||||
"id": "Z1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Base-M",
|
||||
"coords": [
|
||||
3.6576,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Base-R",
|
||||
"coords": [
|
||||
4.2672,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Crown",
|
||||
"coords": [
|
||||
1.8288,
|
||||
2.4383999999999997,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Steel-3000ksi",
|
||||
"type": "Elastic",
|
||||
"E": 20685000000.0,
|
||||
"eta": 0.0,
|
||||
"Eneg": null
|
||||
}
|
||||
],
|
||||
"sections": [],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Bar-1-4",
|
||||
"type": "Truss",
|
||||
"nodes": [
|
||||
1,
|
||||
4
|
||||
],
|
||||
"area": 0.0064516,
|
||||
"material_id": 1,
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Bar-2-4",
|
||||
"type": "Truss",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"area": 0.0032258,
|
||||
"material_id": 1,
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Bar-3-4",
|
||||
"type": "Truss",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"area": 0.0032258,
|
||||
"material_id": 1,
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Ramp",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Tip Load",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 4,
|
||||
"forces": [
|
||||
444822.16,
|
||||
-222411.08,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Static",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 1,
|
||||
"load_factor_increment": 1.0,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Linear",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-08,
|
||||
"max_iter": 25
|
||||
}
|
||||
]
|
||||
}
|
||||
163
examples/basic_truss.py
Normal file
163
examples/basic_truss.py
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
"""Basic Truss Example — OpenSees Examples Manual, Example 1 (exact geometry).
|
||||
|
||||
Three-bar pin-jointed truss in 2D under a nodal load at the crown.
|
||||
|
||||
Geometry as in the OpenSees Tcl script (units: kip, in)::
|
||||
|
||||
node 1 0.0 0.0 node 4 72.0 96.0
|
||||
node 2 144.0 0.0 (crown — loaded here)
|
||||
node 3 168.0 0.0
|
||||
─── Note the asymmetry:
|
||||
Base nodes: node 2 at x=144"
|
||||
(0, 0) ───────── (144, 0) ── (168, 0) node 3 at x=168"
|
||||
↑ ↑ (only 24" apart!)
|
||||
|
||||
This is an asymmetric three-bar truss reaching to a single crown
|
||||
joint (node 4) at the top. The three bars have different lengths
|
||||
and two different areas (bar 1 = 10 in², bars 2 and 3 = 5 in²).
|
||||
|
||||
Loads (at node 4): Fx = +100 kip, Fy = -50 kip.
|
||||
Material: Elastic, E = 3000 ksi.
|
||||
|
||||
Analytical solution in kip-in units (verified by OpenSees Tcl run):
|
||||
u_x(node 4) ≈ +0.530 in
|
||||
u_y(node 4) ≈ -0.178 in
|
||||
|
||||
In OTKO we always work in SI internally (m, N), so we
|
||||
convert inches → metres (×0.0254), kips → newtons (×4448.22) and
|
||||
ksi → pascals (×6.895e6). The converted model gives the same
|
||||
dimensionless solution when you multiply back by the inverse
|
||||
conversion.
|
||||
|
||||
Produces ``examples/basic_truss.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
CoordinateGridSystem,
|
||||
ElasticUniaxial,
|
||||
GridSystem,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
StaticCase,
|
||||
TrussElement,
|
||||
UnitSystem,
|
||||
make_grid_lines,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
# Unit conversions (imperial → SI).
|
||||
IN_TO_M = 0.0254
|
||||
KIP_TO_N = 4448.2216
|
||||
KSI_TO_PA = 6.895e6
|
||||
|
||||
|
||||
def build_basic_truss() -> Project:
|
||||
"""Three-bar planar truss — Example 1 of the OpenSees user manual.
|
||||
|
||||
Geometry in inches → metres; material E in ksi → Pa; areas in
|
||||
in² → m²; loads in kips → N. The SI model is a dimensionless
|
||||
scale of the original kip-in model, so the OpenSees solve gives
|
||||
the same shape / ratio of displacements.
|
||||
"""
|
||||
# Node coordinates in inches (from Tcl) — converted to metres.
|
||||
x1, y1 = 0.0, 0.0
|
||||
x2, y2 = 144.0, 0.0
|
||||
x3, y3 = 168.0, 0.0
|
||||
x4, y4 = 72.0, 96.0
|
||||
|
||||
# Areas in in² — converted to m².
|
||||
a1 = 10.0 * IN_TO_M ** 2
|
||||
a2 = 5.0 * IN_TO_M ** 2
|
||||
a3 = 5.0 * IN_TO_M ** 2
|
||||
|
||||
# Loads in kips — converted to N.
|
||||
fx = 100.0 * KIP_TO_N
|
||||
fy = -50.0 * KIP_TO_N
|
||||
|
||||
# Material E in ksi → Pa.
|
||||
e = 3000.0 * KSI_TO_PA
|
||||
|
||||
# Grid that covers all four nodes (for the canvas overlay).
|
||||
x_ords = [x1 * IN_TO_M, x4 * IN_TO_M, x2 * IN_TO_M, x3 * IN_TO_M]
|
||||
y_ords = [y1 * IN_TO_M, y4 * IN_TO_M]
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Basic Truss",
|
||||
author="OpenSees Examples Manual - Example 1",
|
||||
description="3-bar asymmetric planar truss, linear static analysis.",
|
||||
units=UnitSystem.SI_M_N,
|
||||
),
|
||||
ndm=2, ndf=2,
|
||||
coord_systems=[
|
||||
CoordinateGridSystem(
|
||||
name="Global",
|
||||
grid=GridSystem(
|
||||
x_grid_lines=make_grid_lines("X", x_ords),
|
||||
y_grid_lines=make_grid_lines("Y", y_ords),
|
||||
z_grid_lines=make_grid_lines("Z", [0.0]),
|
||||
),
|
||||
),
|
||||
],
|
||||
nodes=[
|
||||
Node(id=1, name="Base-L", coords=(x1 * IN_TO_M, y1 * IN_TO_M, 0.0),
|
||||
restraint=(True, True, False, False, False, False)),
|
||||
Node(id=2, name="Base-M", coords=(x2 * IN_TO_M, y2 * IN_TO_M, 0.0),
|
||||
restraint=(True, True, False, False, False, False)),
|
||||
Node(id=3, name="Base-R", coords=(x3 * IN_TO_M, y3 * IN_TO_M, 0.0),
|
||||
restraint=(True, True, False, False, False, False)),
|
||||
Node(id=4, name="Crown", coords=(x4 * IN_TO_M, y4 * IN_TO_M, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
ElasticUniaxial(id=1, name="Steel-3000ksi", E=e),
|
||||
],
|
||||
sections=[],
|
||||
elements=[
|
||||
TrussElement(id=1, name="Bar-1-4", nodes=(1, 4),
|
||||
area=a1, material_id=1),
|
||||
TrussElement(id=2, name="Bar-2-4", nodes=(2, 4),
|
||||
area=a2, material_id=1),
|
||||
TrussElement(id=3, name="Bar-3-4", nodes=(3, 4),
|
||||
area=a3, material_id=1),
|
||||
],
|
||||
time_series=[LinearTimeSeries(id=1, name="Ramp")],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1, name="Tip Load",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=4, forces=(fx, fy, 0, 0, 0, 0)),
|
||||
],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(id=1, name="Static", pattern_ids=[1], n_steps=1),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_basic_truss()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}' - {len(project.nodes)} nodes, "
|
||||
f"{len(project.elements)} truss bars, {len(project.analyses)} case.")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
3483
examples/beam_quad_2d.osmodel
Normal file
3483
examples/beam_quad_2d.osmodel
Normal file
File diff suppressed because it is too large
Load diff
200
examples/beam_quad_2d.py
Normal file
200
examples/beam_quad_2d.py
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
"""Simply Supported Beam with 2D Solid (Quad) Elements — OpenSees Ex 6.4.
|
||||
|
||||
A 40" × 10" simply supported deep beam meshed with 16×4 plane-stress
|
||||
quadrilateral elements under two centre-span vertical loads (one at the
|
||||
top midspan, one at the bottom midspan, each 1 kip downward). The
|
||||
load is ramped up over 10 LoadControl steps, giving a final midspan
|
||||
deflection of ~0.394 in. A second case then *removes* the preload and
|
||||
lets the beam free-vibrate with 2% stiffness-proportional damping for
|
||||
1500 Newmark steps at dt = 0.5 s — reproducing the full Tcl flow.
|
||||
|
||||
Matches the Tcl walkthrough at:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=Simply_supported_beam_modeled_with_two_dimensional_solid_elements
|
||||
|
||||
Model (kip, in, sec):
|
||||
- Geometry: L = 40 in, H = 10 in, t = 1 in (plane stress)
|
||||
- Material: ElasticIsotropic — E = 1000 ksi, ν = 0.25, ρ = 3.0
|
||||
- Elements: 16 × 4 = 64 four-node quads (``quad`` variant,
|
||||
``PlaneStress2D`` formulation)
|
||||
- Supports: pin at node 1 (bottom-left), roller at node 17
|
||||
(bottom-right, Uy restrained only)
|
||||
- Loads: 2 × 1 kip ↓ at (20, 0) and (20, 10), ramped via
|
||||
LoadControl from 0 to 10 over 10 steps
|
||||
|
||||
Analysis cases:
|
||||
1. ``Static`` — 10-step LoadControl, midspan Uy ≈ -0.394 in
|
||||
2. ``FreeVibration`` — Transient with preload = case 1, remove
|
||||
pattern 1, Newmark (γ=0.5, β=0.25), dt = 0.5 s, 1500 steps,
|
||||
βK auto-computed from 2% damping at the 1st mode.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
ElasticIsotropic,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
QuadElement,
|
||||
StaticCase,
|
||||
TransientCase,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
# Geometry (inches).
|
||||
L = 40.0
|
||||
H = 10.0
|
||||
THICKNESS = 1.0
|
||||
|
||||
# Mesh — nx must be even so a node lands at the midspan.
|
||||
NX = 16
|
||||
NY = 4
|
||||
|
||||
# Material (kip-in units).
|
||||
E = 1000.0
|
||||
NU = 0.25
|
||||
RHO = 3.0
|
||||
|
||||
|
||||
def _node_id(i: int, j: int) -> int:
|
||||
"""Row-major node id (matching the Tcl ``block2D`` numbering).
|
||||
|
||||
i = 0..NX column index (along length), j = 0..NY row index (through depth).
|
||||
"""
|
||||
return j * (NX + 1) + i + 1
|
||||
|
||||
|
||||
def _mid_bottom_node_id() -> int:
|
||||
"""Node at (L/2, 0) — bottom flange midspan where one load attaches."""
|
||||
return _node_id(NX // 2, 0)
|
||||
|
||||
|
||||
def _mid_top_node_id() -> int:
|
||||
"""Node at (L/2, H) — top flange midspan where the other load attaches."""
|
||||
return _node_id(NX // 2, NY)
|
||||
|
||||
|
||||
def _right_bottom_node_id() -> int:
|
||||
"""Bottom-right corner — the roller support."""
|
||||
return _node_id(NX, 0)
|
||||
|
||||
|
||||
def build_beam_quad_2d() -> Project:
|
||||
dx = L / NX
|
||||
dy = H / NY
|
||||
|
||||
nodes: list[Node] = []
|
||||
for j in range(NY + 1):
|
||||
for i in range(NX + 1):
|
||||
nid = _node_id(i, j)
|
||||
if nid == 1:
|
||||
restraint = (True, True, False, False, False, False) # pin
|
||||
elif nid == _right_bottom_node_id():
|
||||
restraint = (False, True, False, False, False, False) # roller (Uy only)
|
||||
else:
|
||||
restraint = (False,) * 6
|
||||
nodes.append(Node(
|
||||
id=nid, name=f"N{nid}",
|
||||
coords=(i * dx, j * dy, 0.0),
|
||||
restraint=restraint,
|
||||
))
|
||||
|
||||
elements: list[QuadElement] = []
|
||||
eid = 1
|
||||
for j in range(NY):
|
||||
for i in range(NX):
|
||||
n1 = _node_id(i, j) # bottom-left
|
||||
n2 = _node_id(i + 1, j) # bottom-right
|
||||
n3 = _node_id(i + 1, j + 1) # top-right
|
||||
n4 = _node_id(i, j + 1) # top-left (counter-clockwise)
|
||||
elements.append(QuadElement(
|
||||
id=eid, name=f"Q{eid}",
|
||||
nodes=(n1, n2, n3, n4),
|
||||
thickness=THICKNESS,
|
||||
material_id=1,
|
||||
variant="quad",
|
||||
behaviour="PlaneStress2D",
|
||||
))
|
||||
eid += 1
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Simply Supported Beam — Quad Elements (OpenSees Ex 6.4)",
|
||||
author="OpenSees Examples Manual",
|
||||
description=(
|
||||
f"{NX}×{NY} plane-stress quad mesh of a {L:.0f}×{H:.0f} deep "
|
||||
"beam with two midspan point loads, LoadControl 0→10 in 10 steps."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2, ndf=2,
|
||||
nodes=nodes,
|
||||
materials=[ElasticIsotropic(id=1, name="Elastic", E=E, nu=NU, rho=RHO)],
|
||||
elements=elements,
|
||||
time_series=[LinearTimeSeries(id=1, name="Ramp")],
|
||||
load_patterns=[PlainLoadPattern(
|
||||
id=1, name="MidspanLoad",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=_mid_bottom_node_id(),
|
||||
forces=(0.0, -1.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
NodalLoad(node_id=_mid_top_node_id(),
|
||||
forces=(0.0, -1.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
)],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1, name="Static",
|
||||
pattern_ids=[1],
|
||||
n_steps=10, load_factor_increment=1.0,
|
||||
system="ProfileSPD", constraints="Plain",
|
||||
integrator="LoadControl", algorithm="Newton",
|
||||
test="EnergyIncr", tolerance=1e-12, max_iter=10,
|
||||
),
|
||||
# Free-vibration continuation: runs case 1 to completion,
|
||||
# drops the midspan load pattern, sets up 2% βK Rayleigh
|
||||
# damping from the 1st mode, then integrates 1500 steps of
|
||||
# Newmark (γ=0.5, β=0.25) at dt = 0.5 s.
|
||||
TransientCase(
|
||||
id=2, name="FreeVibration",
|
||||
preload_case_ids=[1],
|
||||
remove_patterns=[1],
|
||||
pattern_ids=[],
|
||||
dt=0.5, n_steps=1500,
|
||||
system="BandGeneral", constraints="Plain",
|
||||
integrator="Newmark", integrator_params=(0.5, 0.25),
|
||||
algorithm="Newton",
|
||||
test="EnergyIncr", tolerance=1e-12, max_iter=10,
|
||||
rayleigh_mode1_damping=0.02,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_beam_quad_2d()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" ndm={project.ndm}, ndf={project.ndf}, "
|
||||
f"units={project.meta.units.value}")
|
||||
print(f" {len(project.nodes)} nodes, {len(project.elements)} quads")
|
||||
print(f" Midspan loaded nodes: bottom={_mid_bottom_node_id()}, "
|
||||
f"top={_mid_top_node_id()}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
379
examples/cantilever.osmodel
Normal file
379
examples/cantilever.osmodel
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Cantilever",
|
||||
"description": "",
|
||||
"author": "Ozan",
|
||||
"units": "SI (m, N, kg, s, Pa)"
|
||||
},
|
||||
"ndm": 3,
|
||||
"ndf": 6,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "N1",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "N2",
|
||||
"coords": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
1000.0,
|
||||
1000.0,
|
||||
1000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "N3",
|
||||
"coords": [
|
||||
2.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
1000.0,
|
||||
1000.0,
|
||||
1000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "N4",
|
||||
"coords": [
|
||||
3.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
1000.0,
|
||||
1000.0,
|
||||
1000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "N5",
|
||||
"coords": [
|
||||
4.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
1000.0,
|
||||
1000.0,
|
||||
1000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "N6",
|
||||
"coords": [
|
||||
5.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
1000.0,
|
||||
1000.0,
|
||||
1000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "W12x40",
|
||||
"type": "ElasticSection",
|
||||
"E": 200000000000.0,
|
||||
"A": 0.0076,
|
||||
"Iz": 0.0002,
|
||||
"Iy": 4.5e-05,
|
||||
"G": 80000000000.0,
|
||||
"J": 8.5e-07
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "E1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "E2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "E3",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "E4",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
4,
|
||||
5
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "E5",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
5,
|
||||
6
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Ramp",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "TipLoad",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 6,
|
||||
"forces": [
|
||||
0.0,
|
||||
-10000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "UniformLoad",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [],
|
||||
"element_loads": [
|
||||
{
|
||||
"element_id": 1,
|
||||
"wy": -2000.0,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 2,
|
||||
"wy": -2000.0,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 3,
|
||||
"wy": -2000.0,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 4,
|
||||
"wy": -2000.0,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 5,
|
||||
"wy": -2000.0,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Tip-Load",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 1,
|
||||
"load_factor_increment": 1.0,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Linear",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-08,
|
||||
"max_iter": 25
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Uniform-Load",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
2
|
||||
],
|
||||
"n_steps": 1,
|
||||
"load_factor_increment": 1.0,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Linear",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-08,
|
||||
"max_iter": 25
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Modal-3",
|
||||
"type": "Modal",
|
||||
"n_modes": 3,
|
||||
"solver": "genBandArpack"
|
||||
}
|
||||
]
|
||||
}
|
||||
121
examples/cantilever.py
Normal file
121
examples/cantilever.py
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
"""Cantilever beam example — ideal for showing force diagrams.
|
||||
|
||||
A 5 m horizontal cantilever fixed at the left end, with a point load
|
||||
at the tip and a distributed-equivalent set of nodal loads along the
|
||||
span. Pure bending response makes for instantly recognisable N/V/M
|
||||
diagrams.
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/cantilever.py
|
||||
|
||||
Produces ``examples/cantilever.osmodel``.
|
||||
Open in the GUI, run "Tip-Load" Static case, then:
|
||||
|
||||
Display → Show Force Diagram → V2 (shear) → constant within each segment
|
||||
Display → Show Force Diagram → M3 (moment) → linear, max at the fixed end
|
||||
Display → Show Deformed Shape → classic cantilever curve
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
ModalCase,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
StaticCase,
|
||||
UniformElementLoad,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
def build_cantilever() -> Project:
|
||||
"""5 m cantilever discretised into 5 elements (1 m each)."""
|
||||
n_segments = 5
|
||||
seg_len = 1.0
|
||||
nodes = []
|
||||
for i in range(n_segments + 1):
|
||||
x = i * seg_len
|
||||
restraint = (True,) * 6 if i == 0 else (False,) * 6
|
||||
# Lump some mass at every free node so modal works too.
|
||||
mass = (1000.0, 1000.0, 1000.0, 0.0, 0.0, 0.0) if i > 0 else (0.0,) * 6
|
||||
nodes.append(Node(id=i + 1, name=f"N{i+1}",
|
||||
coords=(x, 0.0, 0.0), restraint=restraint, mass=mass))
|
||||
|
||||
elements = [
|
||||
ElasticBeamColumn(id=i + 1, name=f"E{i+1}",
|
||||
nodes=(i + 1, i + 2), section_id=1)
|
||||
for i in range(n_segments)
|
||||
]
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(name="Cantilever", author="Ozan", units=UnitSystem.SI_M_N),
|
||||
ndm=3, ndf=6,
|
||||
nodes=nodes,
|
||||
sections=[
|
||||
ElasticSection(
|
||||
id=1, name="W12x40",
|
||||
E=200e9, A=0.0076,
|
||||
Iz=2.0e-4, Iy=4.5e-5,
|
||||
G=80e9, J=8.5e-7,
|
||||
),
|
||||
],
|
||||
elements=elements,
|
||||
time_series=[LinearTimeSeries(id=1, name="Ramp")],
|
||||
load_patterns=[
|
||||
# Tip horizontal load (y) of 10 kN — this produces shear V2
|
||||
# and moment M3 about the strong axis, the conventional 2D
|
||||
# "in-plane bending" components.
|
||||
PlainLoadPattern(
|
||||
id=1, name="TipLoad",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=n_segments + 1,
|
||||
forces=(0.0, -10_000.0, 0.0, 0, 0, 0)),
|
||||
],
|
||||
),
|
||||
# Uniform distributed load wy = -2 kN/m along every element.
|
||||
# Produces parabolic moment diagram, max at fixed end
|
||||
# (M_max = q·L²/2 = 2·5²/2 = 25 kN·m).
|
||||
PlainLoadPattern(
|
||||
id=2, name="UniformLoad",
|
||||
time_series_id=1,
|
||||
element_loads=[
|
||||
UniformElementLoad(element_id=i + 1, wy=-2_000.0)
|
||||
for i in range(n_segments)
|
||||
],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(id=1, name="Tip-Load", pattern_ids=[1]),
|
||||
StaticCase(id=2, name="Uniform-Load", pattern_ids=[2]),
|
||||
ModalCase(id=3, name="Modal-3", n_modes=3),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_cantilever()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}' — {len(project.nodes)} nodes, "
|
||||
f"{len(project.elements)} elements, {len(project.analyses)} cases.")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
275
examples/concrete04_cantilever.osmodel
Normal file
275
examples/concrete04_cantilever.osmodel
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Concrete04 Cantilever",
|
||||
"description": "Single RC column cantilever using Concrete04 (Popovics) fiber section. Demonstrates the Concrete04 material end-to-end: schema → model → runner → results.",
|
||||
"author": "",
|
||||
"units": "SI (m, N, kg, s, Pa)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Top",
|
||||
"coords": [
|
||||
0.0,
|
||||
3.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "C30-Popovics",
|
||||
"type": "Concrete04",
|
||||
"fpc": -30000000.0,
|
||||
"epsc0": -0.002,
|
||||
"epscu": -0.005,
|
||||
"Ec": 25742960202.74281,
|
||||
"fct": 2200000.0,
|
||||
"et": 0.0001,
|
||||
"beta": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Rebar-B500",
|
||||
"type": "Steel02",
|
||||
"Fy": 420000000.0,
|
||||
"E0": 200000000000.0,
|
||||
"b": 0.01,
|
||||
"R0": 18.0,
|
||||
"cR1": 0.925,
|
||||
"cR2": 0.15
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "RC-Fiber-C04",
|
||||
"type": "FiberSection",
|
||||
"GJ": null,
|
||||
"patches": [
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 1,
|
||||
"n_fib_y": 8,
|
||||
"n_fib_z": 4,
|
||||
"y_i": -0.15,
|
||||
"z_i": -0.15,
|
||||
"y_j": 0.15,
|
||||
"z_j": 0.15
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 2,
|
||||
"n_bars": 4,
|
||||
"bar_area": 0.000314,
|
||||
"y_start": -0.12,
|
||||
"z_start": 0.12,
|
||||
"y_end": -0.12,
|
||||
"z_end": -0.12
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 2,
|
||||
"n_bars": 4,
|
||||
"bar_area": 0.000314,
|
||||
"y_start": 0.12,
|
||||
"z_start": 0.12,
|
||||
"y_end": 0.12,
|
||||
"z_end": -0.12
|
||||
}
|
||||
],
|
||||
"fibres": []
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Column",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
}
|
||||
],
|
||||
"mp_constraints": [],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Lateral",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 2,
|
||||
"forces": [
|
||||
0.0,
|
||||
-300000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Pushover-X",
|
||||
"type": "Plain",
|
||||
"time_series_id": 2,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 2,
|
||||
"forces": [
|
||||
50000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 10,
|
||||
"load_factor_increment": 0.1,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-08,
|
||||
"max_iter": 10
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Push-X",
|
||||
"type": "Pushover",
|
||||
"pattern_ids": [
|
||||
2
|
||||
],
|
||||
"control_node": 2,
|
||||
"control_dof": 1,
|
||||
"target_disp": 0.15000000000000002,
|
||||
"step_size": 0.003,
|
||||
"base_nodes": [
|
||||
1
|
||||
],
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"algorithm": "Newton",
|
||||
"test": "EnergyIncr",
|
||||
"tolerance": 1e-08,
|
||||
"max_iter": 10,
|
||||
"preload_case_ids": [
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
215
examples/concrete04_cantilever.py
Normal file
215
examples/concrete04_cantilever.py
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
"""Concrete04 (Popovics) fiber-section cantilever.
|
||||
|
||||
A single reinforced-concrete column cantilever using Concrete04 as the
|
||||
fiber material, mirroring the ex2c_canti2d_inelastic_fiber_section example
|
||||
but with Popovics concrete in place of Kent-Scott-Park (Concrete02).
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/concrete04_cantilever.py
|
||||
|
||||
Produces ``examples/concrete04_cantilever.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
Concrete04,
|
||||
FiberSection,
|
||||
ForceBeamColumn,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
RectangularPatch,
|
||||
StaticCase,
|
||||
Steel02,
|
||||
StraightLayer,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
|
||||
# ── Section geometry (SI units: m, N, Pa) ─────────────────────────────────────
|
||||
L_COL = 3.0 # column height [m]
|
||||
B_COL = 0.30 # section width [m]
|
||||
H_COL = 0.30 # section depth [m]
|
||||
COVER = 0.03 # clear cover [m]
|
||||
|
||||
# ── Material parameters (SI) ───────────────────────────────────────────────────
|
||||
FC = -30e6 # peak compressive strength [Pa] (negative)
|
||||
EPSC0 = -0.002 # strain at peak
|
||||
EPSCU = -0.005 # ultimate compressive strain
|
||||
# Initial tangent: Ec = 4700 * sqrt(|fc| / 1e6) MPa (ACI 318 formula, SI)
|
||||
EC = 4700.0 * math.sqrt(abs(FC) / 1e6) * 1e6 # ≈ 25.74 GPa
|
||||
|
||||
FCT = 2.2e6 # tensile strength [Pa]
|
||||
ET = 1e-4 # ultimate tensile strain
|
||||
|
||||
FY = 420e6 # rebar yield stress [Pa]
|
||||
ES = 200e9 # rebar elastic modulus [Pa]
|
||||
BS = 0.01 # strain-hardening ratio
|
||||
|
||||
NUM_INT_PTS = 5
|
||||
N_BARS = 4
|
||||
BAR_AREA = 314e-6 # m² (≈ 20 mm diameter rebar)
|
||||
|
||||
P_GRAVITY = -300e3 # gravity axial load [N] (negative = compressive)
|
||||
H_LOAD = 50e3 # lateral load at tip [N]
|
||||
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
|
||||
PUSH_TARGET = 0.05 * L_COL # [m]
|
||||
PUSH_STEP = 0.001 * L_COL # [m]
|
||||
|
||||
|
||||
def build_concrete04_cantilever() -> Project:
|
||||
core_y = H_COL / 2.0 - COVER
|
||||
core_z = B_COL / 2.0 - COVER
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Concrete04 Cantilever",
|
||||
description=(
|
||||
"Single RC column cantilever using Concrete04 (Popovics) "
|
||||
"fiber section. Demonstrates the Concrete04 material "
|
||||
"end-to-end: schema → model → runner → results."
|
||||
),
|
||||
units=UnitSystem.SI_M_N,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1, name="Base",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, True, False, False, False),
|
||||
),
|
||||
Node(id=2, name="Top", coords=(0.0, L_COL, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
Concrete04(
|
||||
id=1, name="C30-Popovics",
|
||||
fpc=FC, epsc0=EPSC0, epscu=EPSCU, Ec=EC,
|
||||
fct=FCT, et=ET,
|
||||
),
|
||||
Steel02(
|
||||
id=2, name="Rebar-B500",
|
||||
Fy=FY, E0=ES, b=BS,
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
FiberSection(
|
||||
id=1, name="RC-Fiber-C04",
|
||||
patches=[
|
||||
RectangularPatch(
|
||||
material_id=1,
|
||||
n_fib_y=8, n_fib_z=4,
|
||||
y_i=-H_COL / 2, z_i=-B_COL / 2,
|
||||
y_j= H_COL / 2, z_j= B_COL / 2,
|
||||
),
|
||||
],
|
||||
layers=[
|
||||
StraightLayer(
|
||||
material_id=2,
|
||||
n_bars=N_BARS, bar_area=BAR_AREA,
|
||||
y_start=-core_y, z_start= core_z,
|
||||
y_end =-core_y, z_end =-core_z,
|
||||
),
|
||||
StraightLayer(
|
||||
material_id=2,
|
||||
n_bars=N_BARS, bar_area=BAR_AREA,
|
||||
y_start= core_y, z_start= core_z,
|
||||
y_end = core_y, z_end =-core_z,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(
|
||||
id=1, name="Column",
|
||||
nodes=(1, 2),
|
||||
section_id=1,
|
||||
integration_points=NUM_INT_PTS,
|
||||
geom_transf="Linear",
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=2, name="Lateral"),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1, name="Gravity", time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(0.0, P_GRAVITY, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=2, name="Pushover-X", time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1, name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=N_GRAVITY,
|
||||
load_factor_increment=GRAVITY_STEP,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2, name="Push-X",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[2],
|
||||
control_node=2,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_concrete04_cantilever()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" L={L_COL} m, BxH={B_COL}x{H_COL} m, Ec={EC/1e9:.2f} GPa")
|
||||
print(f" Gravity + pushover cases: {len(project.analyses)}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1598
examples/data/A10000.txt
Normal file
1598
examples/data/A10000.txt
Normal file
File diff suppressed because it is too large
Load diff
800
examples/data/BM68elc.acc
Normal file
800
examples/data/BM68elc.acc
Normal file
|
|
@ -0,0 +1,800 @@
|
|||
-.1368849E-02 -.1659410E-02 -.1466880E-02 -.6865326E-03 -.6491235E-03
|
||||
-.6172128E-03 -.5942289E-03 -.5720329E-03 -.5517003E-03 -.5367939E-03
|
||||
-.5300330E-03 -.5315104E-03 -.5389920E-03 -.5492582E-03 -.5592027E-03
|
||||
-.5659958E-03 -.5672101E-03 -.5617805E-03 -.5502959E-03 -.5347288E-03
|
||||
-.5176619E-03 -.5013709E-03 -.4873454E-03 -.4763228E-03 -.4683559E-03
|
||||
-.4626830E-03 -.4579708E-03 -.4512405E-03 -.4376077E-03 -.4130071E-03
|
||||
-.3772566E-03 -.3363394E-03 -.3030926E-03 -.2926074E-03 -.3144186E-03
|
||||
-.3668375E-03 -.4373818E-03 -.5104884E-03 -.5745380E-03 -.6248976E-03
|
||||
-.6621411E-03 -.6878470E-03 -.7014600E-03 -.6985488E-03 -.6737667E-03
|
||||
-.6258232E-03 -.5616336E-03 -.4955459E-03 -.4432164E-03 -.4144737E-03
|
||||
-.4103149E-03 -.4251781E-03 -.4493034E-03 -.4742715E-03 -.4942019E-03
|
||||
-.5021476E-03 -.4907415E-03 -.4549906E-03 -.4008473E-03 -.3457893E-03
|
||||
-.3076823E-03 -.2975411E-03 -.3148410E-03 -.3469618E-03 -.3746677E-03
|
||||
-.3814194E-03 -.3598713E-03 -.3127679E-03 -.2503611E-03 -.1870004E-03
|
||||
-.1381307E-03 -.1166398E-03 -.1296596E-03 -.1730662E-03 -.2365307E-03
|
||||
-.3092055E-03 -.3795541E-03 -.4410602E-03 -.4886626E-03 -.5170590E-03
|
||||
-.5252823E-03 -.5139311E-03 -.4858098E-03 -.4459504E-03 -.3992677E-03
|
||||
-.3528575E-03 -.3119584E-03 -.2767747E-03 -.2493392E-03 -.2343354E-03
|
||||
-.2328132E-03 -.2443271E-03 -.2710242E-03 -.3142711E-03 -.3756243E-03
|
||||
-.4585760E-03 -.5641321E-03 -.6901264E-03 -.8277058E-03 -.9398496E-03
|
||||
-.9604577E-03 -.8289034E-03 -.5332316E-03 -.1380318E-03 .2342108E-03
|
||||
.4651973E-03 .5026886E-03 .3746881E-03 .1623773E-03 -.5159882E-04
|
||||
-.2224880E-03 -.3475301E-03 -.4529523E-03 -.5485990E-03 -.5963545E-03
|
||||
-.5423656E-03 -.3657646E-03 -.1048402E-03 .1563278E-03 .3291475E-03
|
||||
.3576328E-03 .2409380E-03 .2377646E-04 -.2316319E-03 -.4694656E-03
|
||||
-.6625028E-03 -.8119362E-03 -.9298628E-03 -.1028468E-02 -.1108383E-02
|
||||
-.1131224E-02 -.1020689E-02 -.7165112E-03 -.2327270E-03 .3181869E-03
|
||||
.7732246E-03 .1012043E-02 .1013671E-02 .8560355E-03 .6690806E-03
|
||||
.5646968E-03 .5919845E-03 .7377345E-03 .9490117E-03 .1157766E-02
|
||||
.1288701E-02 .1282487E-02 .1122759E-02 .8318915E-03 .4619941E-03
|
||||
.7578448E-04 -.2595554E-03 -.4939353E-03 -.6127490E-03 -.6275750E-03
|
||||
-.5752344E-03 -.4995743E-03 -.4264229E-03 -.3601404E-03 -.3004083E-03
|
||||
-.2406227E-03 -.1628483E-03 -.3998632E-04 .1649808E-03 .4539122E-03
|
||||
.7517190E-03 .9316287E-03 .8846478E-03 .5857181E-03 .1074495E-03
|
||||
-.4397852E-03 -.9508948E-03 -.1343749E-02 -.1561289E-02 -.1537678E-02
|
||||
-.1227062E-02 -.6359309E-03 .1519731E-03 .9751270E-03 .1659683E-02
|
||||
.2090323E-02 .2247826E-02 .2201305E-02 .2058203E-02 .1895573E-02
|
||||
.1737760E-02 .1553215E-02 .1242380E-02 .7156433E-03 .5001116E-04
|
||||
-.5054628E-03 -.6890887E-03 -.4238027E-03 .1011130E-03 .5498104E-03
|
||||
.6308834E-03 .2434936E-03 -.5144872E-03 -.1425978E-02 -.2207871E-02
|
||||
-.2588403E-02 -.2416130E-02 -.1701441E-02 -.6324158E-03 .4489725E-03
|
||||
.1181227E-02 .1316547E-02 .7973359E-03 -.2602228E-03 -.1657394E-02
|
||||
-.3151829E-02 -.4439463E-02 -.5178411E-02 -.5151548E-02 -.4419849E-02
|
||||
-.3294586E-02 -.2165649E-02 -.1266916E-02 -.5719502E-03 .1140084E-03
|
||||
.9530592E-03 .1899989E-02 .2754509E-02 .3333837E-02 .3558579E-02
|
||||
.3481950E-02 .3221851E-02 .2824910E-02 .2273374E-02 .1577169E-02
|
||||
.8367896E-03 .2027145E-03 -.2373641E-03 -.4614556E-03 -.4731789E-03
|
||||
-.2183073E-03 .4104828E-03 .1459868E-02 .2860114E-02 .4348360E-02
|
||||
.5528933E-02 .6097511E-02 .5985376E-02 .5383175E-02 .4639648E-02
|
||||
.4059716E-02 .3743902E-02 .3490429E-02 .2858654E-02 .1525807E-02
|
||||
-.3418321E-03 -.2117817E-02 -.3132606E-02 -.3067405E-02 -.2029459E-02
|
||||
-.4221254E-03 .1279269E-02 .2716792E-02 .3687018E-02 .4125139E-02
|
||||
.4074137E-02 .3662913E-02 .3043893E-02 .2233206E-02 .1065048E-02
|
||||
-.5910665E-03 -.2497506E-02 -.4059191E-02 -.4734788E-02 -.4355504E-02
|
||||
-.3183642E-02 -.1697557E-02 -.2707831E-03 .9875352E-03 .2151907E-02
|
||||
.3263816E-02 .4199429E-02 .4759887E-02 .4825527E-02 .4432848E-02
|
||||
.3760105E-02 .3017075E-02 .2350750E-02 .1810708E-02 .1373070E-02
|
||||
.9716151E-03 .5537977E-03 .1551401E-03 -.1146315E-03 -.1525016E-03
|
||||
.8037190E-04 .5542061E-03 .1173618E-02 .1820585E-02 .2425000E-02
|
||||
.2926893E-02 .3238843E-02 .3279656E-02 .2992806E-02 .2362163E-02
|
||||
.1372295E-02 .2313812E-04 -.1448616E-02 -.2543549E-02 -.2850379E-02
|
||||
-.2427525E-02 -.1864917E-02 -.1841201E-02 -.2558433E-02 -.3556204E-02
|
||||
-.4063939E-02 -.3529889E-02 -.1969941E-02 .1971637E-05 .1588542E-02
|
||||
.2244687E-02 .1873185E-02 .7977154E-03 -.5171107E-03 -.1717952E-02
|
||||
-.2648191E-02 -.3320288E-02 -.3766790E-02 -.3906620E-02 -.3602483E-02
|
||||
-.2795473E-02 -.1624758E-02 -.4698606E-03 .2144823E-03 .1413113E-03
|
||||
-.6730203E-03 -.1847835E-02 -.2630158E-02 -.2274249E-02 -.6524350E-03
|
||||
.1573817E-02 .3385189E-02 .4056466E-02 .3445002E-02 .1897480E-02
|
||||
-.7834726E-06 -.1758264E-02 -.3163954E-02 -.4224580E-02 -.4961730E-02
|
||||
-.5277184E-02 -.4996010E-02 -.4023828E-02 -.2450240E-02 -.5552267E-03
|
||||
.1274664E-02 .2708539E-02 .3615917E-02 .4076754E-02 .4278436E-02
|
||||
.4381952E-02 .4374117E-02 .4039416E-02 .3125690E-02 .1526682E-02
|
||||
-.6629957E-03 -.3174034E-02 -.5620508E-02 -.7393678E-02 -.7657670E-02
|
||||
-.5879189E-02 -.2309056E-02 .2104524E-02 .6124863E-02 .8661836E-02
|
||||
.9093149E-02 .7418333E-02 .4183904E-02 .1723107E-03 -.3926354E-02
|
||||
-.7599501E-02 -.1040893E-01 -.1196732E-01 -.1209718E-01 -.1098399E-01
|
||||
-.9148456E-02 -.7211587E-02 -.5598882E-02 -.4332776E-02 -.3016100E-02
|
||||
-.1208796E-02 .1051286E-02 .3165395E-02 .4405513E-02 .4396087E-02
|
||||
.3297939E-02 .1655353E-02 .7416014E-04 -.1064366E-02 -.1709471E-02
|
||||
-.2034871E-02 -.2232056E-02 -.2305923E-02 -.2068891E-02 -.1321939E-02
|
||||
-.8340139E-04 .1261539E-02 .2134704E-02 .2109285E-02 .1105460E-02
|
||||
-.5894554E-03 -.2470004E-02 -.4065335E-02 -.5114128E-02 -.5622219E-02
|
||||
-.5758567E-02 -.5625456E-02 -.5164963E-02 -.4249916E-02 -.2873503E-02
|
||||
-.1300094E-02 -.4597824E-05 .5635215E-03 .2430489E-03 -.7996342E-03
|
||||
-.2202475E-02 -.3517325E-02 -.4370145E-02 -.4594031E-02 -.4247630E-02
|
||||
-.3535756E-02 -.2695440E-02 -.1891009E-02 -.1114788E-02 -.2001966E-03
|
||||
.1063983E-02 .2729472E-02 .4506580E-02 .5904495E-02 .6538514E-02
|
||||
.6304454E-02 .5380864E-02 .4057021E-02 .2569189E-02 .1081627E-02
|
||||
-.2431288E-03 -.1132123E-02 -.1222615E-02 -.2623135E-03 .1692263E-02
|
||||
.4233489E-02 .6691237E-02 .8351827E-02 .8781418E-02 .7993135E-02
|
||||
.6368712E-02 .4417529E-02 .2553299E-02 .9862523E-03 -.2879211E-03
|
||||
-.1353996E-02 -.2215209E-02 -.2753861E-02 -.2802267E-02 -.2290656E-02
|
||||
-.1316115E-02 -.6447474E-04 .1257941E-02 .2452606E-02 .3298001E-02
|
||||
.3545191E-02 .3020925E-02 .1768330E-02 .1555108E-03 -.1161917E-02
|
||||
-.1511165E-02 -.5886191E-03 .1294113E-02 .3326199E-02 .4659119E-02
|
||||
.4817445E-02 .3850162E-02 .2221826E-02 .5993848E-03 -.3028908E-03
|
||||
.4499610E-04 .1757564E-02 .4515811E-02 .7747015E-02 .1080406E-01
|
||||
.1304353E-01 .1395124E-01 .1333330E-01 .1139073E-01 .8626151E-02
|
||||
.5657044E-02 .2991235E-02 .8765410E-03 -.7137361E-03 -.1944390E-02
|
||||
-.2910045E-02 -.3511966E-02 -.3524041E-02 -.2828079E-02 -.1517566E-02
|
||||
.1316982E-03 .1753455E-02 .3100957E-02 .4107929E-02 .4813638E-02
|
||||
.5258774E-02 .5355058E-02 .4944081E-02 .3965876E-02 .2490912E-02
|
||||
.6955959E-03 -.1175544E-02 -.2833030E-02 -.3900410E-02 -.3998603E-02
|
||||
-.2931521E-02 -.8106600E-03 .2012093E-02 .5086689E-02 .7945016E-02
|
||||
.1019194E-01 .1156584E-01 .1204074E-01 .1182632E-01 .1122714E-01
|
||||
.1050766E-01 .9726859E-02 .8686699E-02 .7115794E-02 .4980392E-02
|
||||
.2607636E-02 .4853645E-03 -.1043528E-02 -.2024556E-02 -.2885799E-02
|
||||
-.4165203E-02 -.6174022E-02 -.8735769E-02 -.1119461E-01 -.1278969E-01
|
||||
-.1308059E-01 -.1213089E-01 -.1045354E-01 -.8704736E-02 -.7365831E-02
|
||||
-.6595419E-02 -.6254681E-02 -.6079807E-02 -.5833011E-02 -.5404578E-02
|
||||
-.4812268E-02 -.4096855E-02 -.3282374E-02 -.2382386E-02 -.1371636E-02
|
||||
-.2345010E-03 .1029128E-02 .2427386E-02 .3910080E-02 .5297981E-02
|
||||
.6098532E-02 .5564267E-02 .3285883E-02 -.4251326E-03 -.4773041E-02
|
||||
-.8874927E-02 -.1201173E-01 -.1370493E-01 -.1378610E-01 -.1244907E-01
|
||||
-.1014931E-01 -.7440821E-02 -.4775990E-02 -.2391629E-02 -.3412078E-03
|
||||
.1422210E-02 .2980469E-02 .4361524E-02 .5424185E-02 .5920223E-02
|
||||
.5656604E-02 .4614099E-02 .2987099E-02 .1059008E-02 -.9265047E-03
|
||||
-.2832559E-02 -.4642235E-02 -.6381750E-02 -.7981423E-02 -.9160859E-02
|
||||
-.9536279E-02 -.8840301E-02 -.7065088E-02 -.4407939E-02 -.1073603E-02
|
||||
.2747630E-02 .6774304E-02 .1060120E-01 .1376236E-01 .1586998E-01
|
||||
.1671592E-01 .1635498E-01 .1510440E-01 .1335503E-01 .1139606E-01
|
||||
.9353882E-02 .7269033E-02 .5321099E-02 .3970154E-02 .3756399E-02
|
||||
.4945238E-02 .7369704E-02 .1047504E-01 .1341277E-01 .1519901E-01
|
||||
.1512407E-01 .1319094E-01 .1012762E-01 .6957527E-02 .4458216E-02
|
||||
.2895137E-02 .2114719E-02 .1841946E-02 .1945955E-02 .2461216E-02
|
||||
.3432909E-02 .4777061E-02 .6226826E-02 .7409148E-02 .8047544E-02
|
||||
.8084369E-02 .7690493E-02 .7230160E-02 .7136600E-02 .7601987E-02
|
||||
.8262116E-02 .8252509E-02 .6705430E-02 .3405972E-02 -.9392068E-03
|
||||
-.5076408E-02 -.7945572E-02 -.9148912E-02 -.8901434E-02 -.7674806E-02
|
||||
-.5875240E-02 -.3781398E-02 -.1573361E-02 .5790951E-03 .2473429E-02
|
||||
.3977300E-02 .5076070E-02 .5860220E-02 .6468372E-02 .6916667E-02
|
||||
.7024350E-02 .6537226E-02 .5305538E-02 .3436577E-02 .1270087E-02
|
||||
-.7914175E-03 -.2458895E-02 -.3683615E-02 -.4640394E-02 -.5600477E-02
|
||||
-.6752352E-02 -.8119755E-02 -.9593167E-02 -.1103590E-01 -.1236491E-01
|
||||
-.1357366E-01 -.1471308E-01 -.1572562E-01 -.1632927E-01 -.1607012E-01
|
||||
-.1455760E-01 -.1170511E-01 -.7707945E-02 -.2845726E-02 .2593552E-02
|
||||
.8239099E-02 .1371021E-01 .1861603E-01 .2247447E-01 .2484857E-01
|
||||
.2550516E-01 .2458508E-01 .2256438E-01 .2001827E-01 .1742999E-01
|
||||
.1506325E-01 .1292138E-01 .1082082E-01 .8621126E-02 .6408467E-02
|
||||
.4540162E-02 .3447775E-02 .3325761E-02 .4038313E-02 .5274964E-02
|
||||
.6656132E-02 .7902636E-02 .8921166E-02 .9655239E-02 .9989046E-02
|
||||
.9732258E-02 .8780388E-02 .7159844E-02 .4964532E-02 .2307752E-02
|
||||
-.6598585E-03 -.3801772E-02 -.7083769E-02 -.1046226E-01 -.1390451E-01
|
||||
-.1739559E-01 -.2086425E-01 -.2418894E-01 -.2721328E-01 -.2965826E-01
|
||||
-.3105506E-01 -.3092283E-01 -.2907427E-01 -.2567129E-01 -.2091488E-01
|
||||
-.1488636E-01 -.7665321E-02 .6185650E-03 .9603872E-02 .1826989E-01
|
||||
.2490295E-01 .2781942E-01 .2632389E-01 .2106028E-01 .1353917E-01
|
||||
.5409180E-02 -.2194669E-02 -.8995550E-02 -.1531422E-01 -.2164288E-01
|
||||
-.2810458E-01 -.3396651E-01 -.3805669E-01 -.3954256E-01 -.3823027E-01
|
||||
-.3463815E-01 -.2965534E-01 -.2389699E-01 -.1754370E-01 -.1032278E-01
|
||||
-.1798833E-02 .7899254E-02 .1774161E-01 .2585594E-01 .3026364E-01
|
||||
.3001526E-01 .2568086E-01 .1872162E-01 .1064011E-01 .2562814E-02
|
||||
-.5082948E-02 -.1227003E-01 -.1900838E-01 -.2517957E-01 -.3042440E-01
|
||||
-.3433626E-01 -.3669936E-01 -.3742471E-01 -.3640279E-01 -.3380826E-01
|
||||
-.3004120E-01 -.2557789E-01 -.2102416E-01 -.1677586E-01 -.1282777E-01
|
||||
-.8711441E-02 -.3827573E-02 .1826430E-02 .7539540E-02 .1232010E-01
|
||||
.1540526E-01 .1665511E-01 .1650193E-01 .1552809E-01 .1404259E-01
|
||||
.1197892E-01 .9178393E-02 .5548425E-02 .1189046E-02 -.3380682E-02
|
||||
-.7406748E-02 -.1015732E-01 -.1119443E-01 -.1066680E-01 -.9078330E-02
|
||||
-.6958574E-02 -.4656017E-02 -.2360902E-02 -.7646585E-04 .2316568E-02
|
||||
.4821873E-02 .7298118E-02 .9270378E-02 .9896334E-02 .8407688E-02
|
||||
.4582978E-02 -.1039746E-02 -.7169492E-02 -.1217499E-01 -.1481022E-01
|
||||
-.1481108E-01 -.1275542E-01 -.9714298E-02 -.6894851E-02 -.5083874E-02
|
||||
-.4659003E-02 -.5491210E-02 -.7023740E-02 -.8844939E-02 -.1069379E-01
|
||||
-.1250066E-01 -.1454846E-01 -.1707686E-01 -.1989536E-01 -.2233137E-01
|
||||
-.2337480E-01 -.2216943E-01 -.1848253E-01 -.1266237E-01 -.5488932E-02
|
||||
.1933627E-02 .8465627E-02 .1329814E-01 .1618511E-01 .1730439E-01
|
||||
.1705052E-01 .1586226E-01 .1402368E-01 .1162920E-01 .8715639E-02
|
||||
.5517490E-02 .2446470E-02 -.6760063E-04 -.1730739E-02 -.2643284E-02
|
||||
-.3230591E-02 -.4078908E-02 -.5544881E-02 -.7297788E-02 -.8575398E-02
|
||||
-.8701870E-02 -.7335231E-02 -.4596454E-02 -.1089148E-02 .2308446E-02
|
||||
.4930489E-02 .6542544E-02 .7365063E-02 .8007596E-02 .8993838E-02
|
||||
.1061887E-01 .1289529E-01 .1537708E-01 .1740325E-01 .1855977E-01
|
||||
.1879475E-01 .1823605E-01 .1728071E-01 .1636020E-01 .1557678E-01
|
||||
.1487995E-01 .1410674E-01 .1312163E-01 .1187395E-01 .1047366E-01
|
||||
.9401153E-02 .8976578E-02 .9189091E-02 .9935435E-02 .1091718E-01
|
||||
.1178125E-01 .1219021E-01 .1208668E-01 .1164181E-01 .1092886E-01
|
||||
.1033433E-01 .1044840E-01 .1168691E-01 .1398808E-01 .1657557E-01
|
||||
.1843491E-01 .1882112E-01 .1750543E-01 .1453506E-01 .1014117E-01
|
||||
.4922797E-02 -.1521883E-03 -.3943517E-02 -.5637022E-02 -.5201442E-02
|
||||
-.3427316E-02 -.1447996E-02 -.3824361E-03 -.9026158E-03 -.2899126E-02
|
||||
-.5725932E-02 -.8629017E-02 -.1101399E-01 -.1248361E-01 -.1285285E-01
|
||||
-.1218286E-01 -.1059188E-01 -.8178625E-02 -.4990100E-02 -.1028538E-02
|
||||
.3150664E-02 .6362955E-02 .7546259E-02 .6259687E-02 .2864968E-02
|
||||
-.1635834E-02 -.6229456E-02 -.1030984E-01 -.1363929E-01 -.1633579E-01
|
||||
-.1859400E-01 -.2033242E-01 -.2129428E-01 -.2115705E-01 -.1995381E-01
|
||||
-.1803703E-01 -.1572271E-01 -.1346108E-01 -.1157558E-01 -.1028342E-01
|
||||
-.9973393E-02 -.1088589E-01 -.1283440E-01 -.1521976E-01 -.1700754E-01
|
||||
-.1700241E-01 -.1464764E-01 -.1020196E-01 -.4479077E-02 .1320025E-02
|
||||
.6097918E-02 .9342135E-02 .1111878E-01 .1183866E-01 .1189031E-01
|
||||
.1125836E-01 .9810133E-02 .7402317E-02 .4095284E-02 .1828470E-03
|
||||
-.4088318E-02 -.8438761E-02 -.1270788E-01 -.1650415E-01 -.1902820E-01
|
||||
-.1941728E-01 -.1716774E-01 -.1240415E-01 -.5653437E-02 .2476229E-02
|
||||
.1130678E-01 .1996734E-01 .2754194E-01 .3310088E-01 .3597632E-01
|
||||
.3620774E-01 .3446190E-01 .3184828E-01 .2958874E-01 .2850179E-01
|
||||
.2876039E-01 .2975068E-01 .3013135E-01 .2831505E-01 .2328487E-01
|
||||
.1514390E-01 .4924578E-02 -.5911273E-02 -.1587064E-01 -.2387583E-01
|
||||
-.2952881E-01 -.3279504E-01 -.3384369E-01 -.3301784E-01 -.3063855E-01
|
||||
-.2689125E-01 -.2179400E-01 -.1538950E-01 -.7952897E-02 -.9614722E-06
|
||||
.7845226E-02 .1515901E-01 .2172301E-01 .2721474E-01 .3118629E-01
|
||||
.3321061E-01 .3315358E-01 .3141515E-01 .2869304E-01 .2566259E-01
|
||||
.2279068E-01 .2024065E-01 .1800577E-01 .1598535E-01 .1414388E-01
|
||||
.1245735E-01 .1078543E-01 .8834504E-02 .6219473E-02 .2691722E-02
|
||||
-.1693293E-02 -.6300586E-02 -.1002109E-01 -.1160434E-01 -.1034660E-01
|
||||
-.6522354E-02 -.1193026E-02 .4069759E-02 .7675377E-02 .8652136E-02
|
||||
.7037568E-02 .3689011E-02 -.1703597E-03 -.3524754E-02 -.5959860E-02
|
||||
-.7514396E-02 -.8400751E-02 -.8698959E-02 -.8162413E-02 -.6605212E-02
|
||||
-.4054499E-02 -.7536645E-03 .2726845E-02 .5629213E-02 .7297529E-02
|
||||
.7477676E-02 .6330082E-02 .4341098E-02 .2067891E-02 -.9504297E-04
|
||||
-.1997928E-02 -.3688179E-02 -.5087495E-02 -.5982067E-02 -.6480055E-02
|
||||
-.7252330E-02 -.9021151E-02 -.1171408E-01 -.1436533E-01 -.1583704E-01
|
||||
-.1554842E-01 -.1380533E-01 -.1170943E-01 -.1055543E-01 -.1110769E-01
|
||||
-.1302097E-01 -.1486034E-01 -.1504907E-01 -.1265275E-01 -.7609021E-02
|
||||
-.6534508E-03 .7069084E-02 .1429999E-01 .1976389E-01 .2237736E-01
|
||||
.2172482E-01 .1833358E-01 .1331135E-01 .7787639E-02 .2693778E-02
|
||||
-.1145081E-02 -.3063542E-02 -.2688044E-02 -.1992260E-03 .3516970E-02
|
||||
.7112396E-02 .9205986E-02 .8945032E-02 .6403670E-02 .2372275E-02
|
||||
-.2278300E-02 -.6769582E-02 -.1058472E-01 -.1341400E-01 -.1473648E-01
|
||||
-.1408597E-01 -.1135366E-01 -.6882144E-02 -.1458501E-02 .4002616E-02
|
||||
.8496996E-02 .1090352E-01 .1052907E-01 .7505903E-02 .2602705E-02
|
||||
-.3152815E-02 -.8746525E-02 -.1308470E-01 -.1511365E-01 -.1421543E-01
|
||||
-.1043071E-01 -.4478917E-02 .2554198E-02 .9666669E-02 .1596795E-01
|
||||
.2044187E-01 .2229090E-01 .2108773E-01 .1676433E-01 .9953076E-02
|
||||
.2087643E-02 -.4699501E-02 -.8461761E-02 -.8571464E-02 -.5788908E-02
|
||||
-.1529597E-02 .2786955E-02 .6275468E-02 .8679429E-02 .1002905E-01
|
||||
.1042510E-01 .1004069E-01 .9072301E-02 .7679290E-02 .6074455E-02
|
||||
.4473075E-02 .3067263E-02 .1876768E-02 .8717062E-03 .3874273E-04
|
||||
-.7671303E-03 -.1613149E-02 -.2440585E-02 -.3194246E-02 -.3793401E-02
|
||||
-.4178739E-02 -.4371920E-02 -.4428270E-02 -.4444974E-02 -.4507241E-02
|
||||
-.4583253E-02 -.4686428E-02 -.4835609E-02 -.4934173E-02 -.5009819E-02
|
||||
-.5108526E-02 -.5215524E-02 -.5363476E-02 -.5621534E-02 -.6092668E-02
|
||||
-.6926939E-02 -.8356982E-02 -.1046107E-01 -.1306359E-01 -.1585233E-01
|
||||
-.1816486E-01 -.1922537E-01 -.1863163E-01 -.1631364E-01 -.1262393E-01
|
||||
-.7983982E-02 -.2435903E-02 .3674736E-02 .9291033E-02 .1301129E-01
|
||||
.1388301E-01 .1192520E-01 .7868640E-02 .2877415E-02 -.2157623E-02
|
||||
-.6911937E-02 -.1124143E-01 -.1500486E-01 -.1768727E-01 -.1852320E-01
|
||||
-.1697383E-01 -.1298640E-01 -.7084300E-02 -.7721108E-04 .7034756E-02
|
||||
.1297544E-01 .1665017E-01 .1779682E-01 .1692438E-01 .1496840E-01
|
||||
.1272775E-01 .1023923E-01 .6891558E-02 .1983961E-02 -.4715016E-02
|
||||
-.1287864E-01 -.2164600E-01 -.2960101E-01 -.3515917E-01 -.3713777E-01
|
||||
-.3533459E-01 -.3063518E-01 -.2440813E-01 -.1781452E-01 -.1142552E-01
|
||||
-.5141503E-02 .1498338E-02 .8866538E-02 .1688690E-01 .2470682E-01
|
||||
.3058300E-01 .3238546E-01 .2889857E-01 .2094647E-01 .1083059E-01
|
||||
.9575448E-03 -.7089134E-02 -.1283213E-01 -.1619175E-01 -.1684417E-01
|
||||
-.1445279E-01 -.9549346E-02 -.3879482E-02 .4078140E-03 .1928972E-02
|
||||
.7526545E-03 -.1856707E-02 -.4191256E-02 -.4972957E-02 -.3965310E-02
|
||||
-.2070338E-02 -.7092010E-03 -.9489900E-03 -.3100835E-02 -.6707078E-02
|
||||
-.1080124E-01 -.1430832E-01 -.1612181E-01 -.1518834E-01 -.1123060E-01
|
||||
-.4823611E-02 .3024228E-02 .1071457E-01 .1645373E-01 .1889990E-01
|
||||
.1757643E-01 .1320395E-01 .7106346E-02 .5534812E-03 -.5513032E-02
|
||||
-.1061932E-01 -.1439279E-01 -.1645384E-01 -.1672504E-01 -.1540873E-01
|
||||
-.1275695E-01 -.9118096E-02 -.4867156E-02 -.2455867E-03 .4230080E-02
|
||||
.7672429E-02 .9142766E-02 .8019062E-02 .4453303E-02 -.8225852E-03
|
||||
-.6841658E-02 -.1275177E-01 -.1813499E-01 -.2261233E-01 -.2564713E-01
|
||||
-.2684913E-01 -.2616440E-01 -.2380227E-01 -.1977725E-01 -.1365101E-01
|
||||
-.5088131E-02 .5197379E-02 .1550537E-01 .2408050E-01 .3004262E-01
|
||||
.3360170E-01 .3521722E-01 .3522096E-01 .3380402E-01 .3094955E-01
|
||||
.2685286E-01 .2192577E-01 .1657763E-01 .1121935E-01 .6148842E-02
|
||||
.1575380E-02 -.2472731E-02 -.6185611E-02 -.9684531E-02 -.1308251E-01
|
||||
-.1661101E-01 -.2043943E-01 -.2465044E-01 -.2891475E-01 -.3214394E-01
|
||||
-.3306835E-01 -.3093236E-01 -.2593347E-01 -.1928827E-01 -.1274861E-01
|
||||
-.7825682E-02 -.5133567E-02 -.4425851E-02 -.4818741E-02 -.5252232E-02
|
||||
-.4930240E-02 -.3672806E-02 -.2020577E-02 -.8254652E-03 -.8623670E-03
|
||||
-.2420186E-02 -.5125718E-02 -.8013458E-02 -.9941214E-02 -.1001373E-01
|
||||
-.7816071E-02 -.3770037E-02 .1162191E-02 .6006638E-02 .9756063E-02
|
||||
.1172414E-01 .1180266E-01 .1034587E-01 .8106998E-02 .5764324E-02
|
||||
.3702295E-02 .2109327E-02 .8522273E-03 -.4087143E-03 -.1958545E-02
|
||||
-.3776898E-02 -.5280190E-02 -.5708328E-02 -.4667265E-02 -.2201315E-02
|
||||
.1272191E-02 .5028644E-02 .8190299E-02 .1023330E-01 .1121147E-01
|
||||
.1140253E-01 .1117003E-01 .1078246E-01 .1021337E-01 .9389039E-02
|
||||
.8031923E-02 .5774986E-02 .2565933E-02 -.1537241E-02 -.6345046E-02
|
||||
-.1170225E-01 -.1765976E-01 -.2419191E-01 -.3101631E-01 -.3736947E-01
|
||||
-.4232024E-01 -.4541069E-01 -.4652028E-01 -.4578869E-01 -.4361636E-01
|
||||
-.4038329E-01 -.3636168E-01 -.3167082E-01 -.2655599E-01 -.2157473E-01
|
||||
-.1738166E-01 -.1447114E-01 -.1283825E-01 -.1207965E-01 -.1171937E-01
|
||||
-.1129131E-01 -.1059250E-01 -.9596382E-02 -.8229236E-02 -.6418498E-02
|
||||
-.4035644E-02 -.1143476E-02 .2077366E-02 .5351418E-02 .8341142E-02
|
||||
.1100083E-01 .1331432E-01 .1519221E-01 .1643695E-01 .1674342E-01
|
||||
.1592628E-01 .1411161E-01 .1171599E-01 .9296672E-02 .7472793E-02
|
||||
.6577241E-02 .6637887E-02 .7456219E-02 .8644244E-02 .1005389E-01
|
||||
.1186538E-01 .1417436E-01 .1673345E-01 .1899539E-01 .2042756E-01
|
||||
.2091466E-01 .2054275E-01 .1939914E-01 .1767041E-01 .1535188E-01
|
||||
.1237763E-01 .8704570E-02 .4147236E-02 -.1360430E-02 -.7787316E-02
|
||||
-.1486702E-01 -.2177232E-01 -.2736238E-01 -.3066875E-01 -.3144420E-01
|
||||
-.3027946E-01 -.2814377E-01 -.2601297E-01 -.2455224E-01 -.2386868E-01
|
||||
-.2363605E-01 -.2353825E-01 -.2333943E-01 -.2288862E-01 -.2227907E-01
|
||||
-.2161968E-01 -.2099637E-01 -.2040827E-01 -.1973868E-01 -.1893775E-01
|
||||
-.1797027E-01 -.1667843E-01 -.1487935E-01 -.1246686E-01 -.9483893E-02
|
||||
-.6337230E-02 -.3506977E-02 -.1291572E-02 .2429348E-03 .1248035E-02
|
||||
.1976424E-02 .2601214E-02 .2968768E-02 .2795946E-02 .1798981E-02
|
||||
-.1659973E-03 -.2845534E-02 -.5849434E-02 -.8908303E-02 -.1182109E-01
|
||||
-.1452760E-01 -.1696396E-01 -.1883610E-01 -.1968982E-01 -.1901421E-01
|
||||
-.1669585E-01 -.1313140E-01 -.8861982E-02 -.4456569E-02 -.3243527E-03
|
||||
.3309549E-02 .6103826E-02 .7759009E-02 .8226937E-02 .7582430E-02
|
||||
.6252748E-02 .4737565E-02 .3470717E-02 .3108701E-02 .4169565E-02
|
||||
.6781691E-02 .1079032E-01 .1556154E-01 .2013236E-01 .2382233E-01
|
||||
.2626433E-01 .2745505E-01 .2788424E-01 .2811386E-01 .2843440E-01
|
||||
.2895634E-01 .2960218E-01 .3003924E-01 .3003745E-01 .2953782E-01
|
||||
.2847969E-01 .2723935E-01 .2630562E-01 .2600641E-01 .2686385E-01
|
||||
.2900223E-01 .3201463E-01 .3563619E-01 .3949034E-01 .4313774E-01
|
||||
.4661442E-01 .4993431E-01 .5291145E-01 .5533222E-01 .5665800E-01
|
||||
.5645912E-01 .5503413E-01 .5279327E-01 .5007040E-01 .4737852E-01
|
||||
.4487943E-01 .4235794E-01 .3974572E-01 .3686028E-01 .3368732E-01
|
||||
.3055061E-01 .2781146E-01 .2609253E-01 .2599445E-01 .2757407E-01
|
||||
.3018356E-01 .3314234E-01 .3576748E-01 .3741581E-01 .3763105E-01
|
||||
.3611741E-01 .3313879E-01 .2902728E-01 .2419680E-01 .1935050E-01
|
||||
.1467773E-01 .1004832E-01 .5684898E-02 .1508315E-02 -.2792435E-02
|
||||
-.7023769E-02 -.1107366E-01 -.1449093E-01 -.1658374E-01 -.1736586E-01
|
||||
-.1709493E-01 -.1650190E-01 -.1654562E-01 -.1754671E-01 -.1935994E-01
|
||||
-.2175887E-01 -.2421596E-01 -.2633406E-01 -.2826962E-01 -.3007234E-01
|
||||
-.3178528E-01 -.3368383E-01 -.3588525E-01 -.3838538E-01 -.4116496E-01
|
||||
-.4399211E-01 -.4660682E-01 -.4828366E-01 -.4786318E-01 -.4458027E-01
|
||||
-.3845997E-01 -.3070465E-01 -.2270198E-01 -.1560400E-01 -.1010790E-01
|
||||
-.5980578E-02 -.2772934E-02 -.1713775E-04 .2673980E-02 .5519567E-02
|
||||
.8460680E-02 .1130877E-01 .1401008E-01 .1656949E-01 .1883679E-01
|
||||
.2051101E-01 .2146666E-01 .2153975E-01 .2084240E-01 .1990095E-01
|
||||
.1882448E-01 .1767300E-01 .1666248E-01 .1545950E-01 .1377915E-01
|
||||
.1181045E-01 .9534539E-02 .7009097E-02 .4686050E-02 .2836866E-02
|
||||
.1815343E-02 .1898834E-02 .2840229E-02 .4322539E-02 .5996240E-02
|
||||
.7348233E-02 .7878039E-02 .7258954E-02 .5524328E-02 .2910175E-02
|
||||
-.1192840E-03 -.2709780E-02 -.4433065E-02 -.5095499E-02 -.4517425E-02
|
||||
-.3210972E-02 -.1762970E-02 -.3308239E-03 .6434073E-03 .5748676E-03
|
||||
-.3093338E-03 -.1867950E-02 -.4005723E-02 -.6188342E-02 -.8441897E-02
|
||||
-.1051722E-01 -.1218090E-01 -.1371676E-01 -.1513981E-01 -.1640948E-01
|
||||
-.1758842E-01 -.1881650E-01 -.2002446E-01 -.2117680E-01 -.2218898E-01
|
||||
-.2237774E-01 -.2098826E-01 -.1749785E-01 -.1199713E-01 -.5457907E-02
|
||||
.1176037E-02 .6830883E-02 .1082376E-01 .1318703E-01 .1378624E-01
|
||||
.1277508E-01 .1066039E-01 .7909360E-02 .4877214E-02 .1911501E-02
|
||||
-.9173029E-03 -.3531967E-02 -.5644893E-02 -.7227729E-02 -.8260763E-02
|
||||
-.8706863E-02 -.8740882E-02 -.8710160E-02 -.8780833E-02 -.8929077E-02
|
||||
-.9381925E-02 -.1024996E-01 -.1161204E-01 -.1344303E-01 -.1545313E-01
|
||||
-.1776305E-01 -.2021068E-01 -.2251479E-01 -.2493718E-01 -.2747284E-01
|
||||
-.2994092E-01 -.3222728E-01 -.3362418E-01 -.3316205E-01 -.2992824E-01
|
||||
-.2359221E-01 -.1504628E-01 -.5412169E-02 .4361812E-02 .1344546E-01
|
||||
.2143670E-01 .2826677E-01 .3386766E-01 .3807828E-01 .4080334E-01
|
||||
.4204068E-01 .4194099E-01 .4092351E-01 .3947267E-01 .3785792E-01
|
||||
.3639122E-01 .3513104E-01 .3384689E-01 .3237553E-01 .3047683E-01
|
||||
.2801395E-01 .2530326E-01 .2283371E-01 .2080132E-01 .1963958E-01
|
||||
.1924832E-01 .1914892E-01 .1924157E-01 .1914600E-01 .1868474E-01
|
||||
.1764816E-01 .1598250E-01 .1400698E-01 .1185010E-01 .9535737E-02
|
||||
.7303359E-02 .5424927E-02 .4099336E-02 .3602893E-02 .3813768E-02
|
||||
.4691968E-02 .5982851E-02 .7198455E-02 .8475807E-02 .9704463E-02
|
||||
.1079903E-01 .1199522E-01 .1309921E-01 .1375677E-01 .1337324E-01
|
||||
.1161517E-01 .8665868E-02 .4754639E-02 .3327197E-03 -.4175680E-02
|
||||
-.8638803E-02 -.1292470E-01 -.1677962E-01 -.2002213E-01 -.2245581E-01
|
||||
-.2394014E-01 -.2436307E-01 -.2341324E-01 -.2102749E-01 -.1757305E-01
|
||||
-.1357719E-01 -.9647067E-02 -.6237683E-02 -.3523645E-02 -.1619959E-02
|
||||
-.5938797E-03 -.5873712E-03 -.1729091E-02 -.3658303E-02 -.6054787E-02
|
||||
-.8687612E-02 -.1110900E-01 -.1329320E-01 -.1517378E-01 -.1627424E-01
|
||||
-.1622413E-01 -.1470082E-01 -.1182905E-01 -.8394616E-02 -.5225185E-02
|
||||
-.2862584E-02 -.1459262E-02 -.7402939E-03 -.3132338E-03 .1528705E-03
|
||||
.9427832E-03 .2164652E-02 .3504850E-02 .4956621E-02 .6561044E-02
|
||||
.7926335E-02 .9208951E-02 .1042562E-01 .1143696E-01 .1241714E-01
|
||||
.1325782E-01 .1376058E-01 .1387821E-01 .1354292E-01 .1270655E-01
|
||||
.1164777E-01 .1048626E-01 .8795471E-02 .5968882E-02 .1222028E-02
|
||||
-.5439779E-02 -.1263862E-01 -.1905841E-01 -.2380396E-01 -.2617362E-01
|
||||
-.2597806E-01 -.2335960E-01 -.1890640E-01 -.1330358E-01 -.7446688E-02
|
||||
-.2739187E-02 .2071204E-03 .1429036E-02 .1028736E-02 -.2401374E-03
|
||||
-.1668075E-02 -.2988337E-02 -.4067810E-02 -.5173909E-02 -.6483773E-02
|
||||
-.7750192E-02 -.8730304E-02 -.9183981E-02 -.8757737E-02 -.7443620E-02
|
||||
-.5621340E-02 -.3618324E-02 -.1583880E-02 .3090976E-03 .1956134E-02
|
||||
.3648367E-02 .5579855E-02 .7890413E-02 .1081725E-01 .1419929E-01
|
||||
.1720072E-01 .1915609E-01 .1985558E-01 .1925274E-01 .1788514E-01
|
||||
.1630675E-01 .1477740E-01 .1338977E-01 .1196436E-01 .1022575E-01
|
||||
.8064738E-02 .5583655E-02 .3000570E-02 .5331712E-03 -.1379636E-02
|
||||
-.2426841E-02 -.2616121E-02 -.2013066E-02 -.1077223E-02 -.2170750E-03
|
||||
.2452922E-03 -.1324171E-03 -.1388844E-02 -.3343876E-02 -.5693895E-02
|
||||
-.8076184E-02 -.1041739E-01 -.1256042E-01 -.1441242E-01 -.1609455E-01
|
||||
-.1746467E-01 -.1859309E-01 -.1958296E-01 -.2029965E-01 -.2088517E-01
|
||||
-.2118079E-01 -.2093396E-01 -.2022643E-01 -.1911941E-01 -.1776040E-01
|
||||
-.1627488E-01 -.1464481E-01 -.1261195E-01 -.9632813E-02 -.5389511E-02
|
||||
-.7220652E-04 .5642729E-02 .1097859E-01 .1545286E-01 .1863852E-01
|
||||
.2052978E-01 .2124407E-01 .2077740E-01 .1950230E-01 .1778722E-01
|
||||
.1596091E-01 .1415971E-01 .1250467E-01 .1113676E-01 .1000036E-01
|
||||
.9128085E-02 .8438501E-02 .7807495E-02 .7209282E-02 .6562780E-02
|
||||
.5611157E-02 .4104884E-02 .1836216E-02 -.1142869E-02 -.4689413E-02
|
||||
-.8478513E-02 -.1198585E-01 -.1467946E-01 -.1589029E-01 -.1564526E-01
|
||||
-.1418316E-01 -.1176374E-01 -.8850510E-02 -.5673143E-02 -.2510591E-02
|
||||
.1802678E-03 .2025823E-02 .3032400E-02 .3425292E-02 .3508645E-02
|
||||
.3676629E-02 .4091425E-02 .4682304E-02 .5472754E-02 .6452162E-02
|
||||
.7347295E-02 .7999419E-02 .8296611E-02 .7928995E-02 .6813268E-02
|
||||
.5011843E-02 .2802597E-02 .4992408E-03 -.1831118E-02 -.4069736E-02
|
||||
-.6046223E-02 -.7749683E-02 -.9061467E-02 -.9705197E-02 -.9636080E-02
|
||||
-.9016790E-02 -.8174797E-02 -.7198690E-02 -.6204959E-02 -.5373029E-02
|
||||
-.4344859E-02 -.2803768E-02 -.5525524E-03 .2538277E-02 .6235031E-02
|
||||
.1016038E-01 .1387329E-01 .1677467E-01 .1827768E-01 .1816112E-01
|
||||
.1658768E-01 .1412021E-01 .1139746E-01 .8696474E-02 .6208537E-02
|
||||
.3969926E-02 .1747097E-02 -.5591269E-03 -.2936676E-02 -.5368648E-02
|
||||
-.7513072E-02 -.8918480E-02 -.9102443E-02 -.7764897E-02 -.5171679E-02
|
||||
-.1761796E-02 .1879600E-02 .5135838E-02 .7591760E-02 .9053612E-02
|
||||
.9685827E-02 .9766829E-02 .9580221E-02 .9451962E-02 .9444144E-02
|
||||
.9532332E-02 .9651165E-02 .9750393E-02 .9941313E-02 .1041583E-01
|
||||
.1151542E-01 .1339452E-01 .1591906E-01 .1877037E-01 .2152736E-01
|
||||
.2384239E-01 .2559043E-01 .2692286E-01 .2806866E-01 .2907231E-01
|
||||
.2980794E-01 .3000675E-01 .2939602E-01 .2797701E-01 .2590633E-01
|
||||
.2358968E-01 .2134617E-01 .1922584E-01 .1733120E-01 .1554119E-01
|
||||
.1381606E-01 .1229399E-01 .1111732E-01 .1066441E-01 .1103057E-01
|
||||
.1204131E-01 .1338293E-01 .1450729E-01 .1504738E-01 .1478665E-01
|
||||
.1374486E-01 .1226510E-01 .1067453E-01 .9171079E-02 .7956521E-02
|
||||
.7243112E-02 .7133591E-02 .7548334E-02 .8351206E-02 .9329349E-02
|
||||
.1033786E-01 .1134440E-01 .1219463E-01 .1297151E-01 .1378645E-01
|
||||
.1454178E-01 .1516388E-01 .1552029E-01 .1536431E-01 .1441286E-01
|
||||
.1276976E-01 .1072529E-01 .8463387E-02 .6392266E-02 .4752372E-02
|
||||
.3457876E-02 .2437014E-02 .1596681E-02 .5628094E-03 -.1049293E-02
|
||||
-.3360829E-02 -.6548210E-02 -.1039057E-01 -.1454904E-01 -.1884158E-01
|
||||
-.2302796E-01 -.2708942E-01 -.3096956E-01 -.3458155E-01 -.3761068E-01
|
||||
-.3953193E-01 -.4003705E-01 -.3918434E-01 -.3738913E-01 -.3518965E-01
|
||||
-.3320436E-01 -.3165300E-01 -.3067854E-01 -.3044658E-01 -.3076029E-01
|
||||
-.3149571E-01 -.3248234E-01 -.3358702E-01 -.3468694E-01 -.3569531E-01
|
||||
-.3663265E-01 -.3748605E-01 -.3817463E-01 -.3864487E-01 -.3896101E-01
|
||||
-.3913047E-01 -.3926949E-01 -.3946818E-01 -.3963120E-01 -.3984169E-01
|
||||
-.4010381E-01 -.4030988E-01 -.4048733E-01 -.4068742E-01 -.4091181E-01
|
||||
-.4108314E-01 -.4134737E-01 -.4164515E-01 -.4191625E-01 -.4221260E-01
|
||||
-.4250566E-01 -.4284395E-01 -.4312954E-01 -.4330667E-01 -.4334183E-01
|
||||
-.4308501E-01 -.4222350E-01 -.4073786E-01 -.3880898E-01 -.3658534E-01
|
||||
-.3430503E-01 -.3193513E-01 -.2939320E-01 -.2643007E-01 -.2268951E-01
|
||||
-.1838666E-01 -.1380213E-01 -.9347827E-02 -.5776366E-02 -.3465915E-02
|
||||
-.2368894E-02 -.2129215E-02 -.2258109E-02 -.2351747E-02 -.2196853E-02
|
||||
-.1854580E-02 -.1449342E-02 -.9127997E-03 -.1951298E-03 .7112905E-03
|
||||
.2021865E-02 .3688877E-02 .5545756E-02 .7607521E-02 .9759494E-02
|
||||
.1173481E-01 .1307648E-01 .1348676E-01 .1280592E-01 .1113297E-01
|
||||
.8912421E-02 .6391149E-02 .3905114E-02 .1601427E-02 -.6692400E-03
|
||||
-.2717528E-02 -.4174201E-02 -.4627424E-02 -.3727393E-02 -.1547067E-02
|
||||
.1500089E-02 .4950034E-02 .8360430E-02 .1141537E-01 .1397295E-01
|
||||
.1600148E-01 .1754447E-01 .1868035E-01 .1966211E-01 .2055389E-01
|
||||
.2138742E-01 .2237416E-01 .2335756E-01 .2431197E-01 .2537448E-01
|
||||
.2656551E-01 .2791929E-01 .2965010E-01 .3174222E-01 .3383392E-01
|
||||
.3578273E-01 .3710474E-01 .3739960E-01 .3679326E-01 .3536805E-01
|
||||
.3346081E-01 .3159161E-01 .2981960E-01 .2811941E-01 .2658930E-01
|
||||
.2499555E-01 .2309543E-01 .2088378E-01 .1841231E-01 .1567525E-01
|
||||
.1284477E-01 .1015462E-01 .7788366E-02 .6110006E-02 .5402534E-02
|
||||
.5638440E-02 .6563084E-02 .7850387E-02 .9206303E-02 .1031194E-01
|
||||
.1098126E-01 .1114542E-01 .1074463E-01 .9957830E-02 .8947896E-02
|
||||
.7833102E-02 .6707737E-02 .5635129E-02 .4515381E-02 .3035268E-02
|
||||
.9134036E-03 -.1856914E-02 -.4957733E-02 -.8185762E-02 -.1104210E-01
|
||||
-.1317374E-01 -.1469623E-01 -.1536370E-01 -.1512908E-01 -.1424074E-01
|
||||
-.1287377E-01 -.1122237E-01 -.9534758E-02 -.7934308E-02 -.6283240E-02
|
||||
-.4473937E-02 -.2516351E-02 -.4075612E-03 .1761349E-02 .3631932E-02
|
||||
.5185014E-02 .6550926E-02 .7627133E-02 .8434078E-02 .8885753E-02
|
||||
.8896488E-02 .8412189E-02 .7505225E-02 .6435478E-02 .5327768E-02
|
||||
.4238728E-02 .3224385E-02 .2239655E-02 .1074355E-02 -.3118892E-03
|
||||
-.1826858E-02 -.3254363E-02 -.4210919E-02 -.4456596E-02 -.3901531E-02
|
||||
-.2794523E-02 -.1524628E-02 -.2957599E-03 .6724922E-03 .1142362E-02
|
||||
.1047438E-02 .4277500E-03 -.6598095E-03 -.1989157E-02 -.3279215E-02
|
||||
-.4515194E-02 -.5755661E-02 -.6996466E-02 -.8379105E-02 -.1009309E-01
|
||||
-.1231685E-01 -.1502015E-01 -.1803725E-01 -.2123054E-01 -.2439197E-01
|
||||
-.2726311E-01 -.2962468E-01 -.3126173E-01 -.3180346E-01 -.3114895E-01
|
||||
-.2959152E-01 -.2749439E-01 -.2527780E-01 -.2314585E-01 -.2111495E-01
|
||||
-.1910038E-01 -.1695931E-01 -.1471179E-01 -.1232559E-01 -.9847208E-02
|
||||
-.7431594E-02 -.5289531E-02 -.3606317E-02 -.2274182E-02 -.1241455E-02
|
||||
-.4807131E-03 .2867630E-03 .1090648E-02 .1916820E-02 .2861809E-02
|
||||
.3882653E-02 .5057116E-02 .6342610E-02 .7716291E-02 .9006579E-02
|
||||
.9757320E-02 .9773900E-02 .9016858E-02 .7676922E-02 .5968230E-02
|
||||
.4131218E-02 .2508963E-02 .1022927E-02 -.4677441E-03 -.1886409E-02
|
||||
-.3108552E-02 -.4005146E-02 -.4412478E-02 -.4230130E-02 -.3596251E-02
|
||||
-.2757693E-02 -.1864050E-02 -.9833094E-03 -.2448452E-03 .4160564E-03
|
||||
.1151147E-02 .1935780E-02 .2790786E-02 .3850240E-02 .5098510E-02
|
||||
.6396557E-02 .7825588E-02 .9341879E-02 .1066413E-01 .1168302E-01
|
||||
.1234519E-01 .1258490E-01 .1257384E-01 .1249794E-01 .1239264E-01
|
||||
.1241063E-01 .1266978E-01 .1319696E-01 .1395792E-01 .1486491E-01
|
||||
.1588669E-01 .1690460E-01 .1783274E-01 .1878446E-01 .1975388E-01
|
||||
.2068742E-01 .2156174E-01 .2217118E-01 .2235588E-01 .2188751E-01
|
||||
.2072463E-01 .1910627E-01 .1721580E-01 .1530059E-01 .1345308E-01
|
||||
.1165164E-01 .9748835E-02 .7580274E-02 .5059838E-02 .2181048E-02
|
||||
-.8965093E-03 -.4099195E-02 -.7276131E-02 -.1024968E-01 -.1300149E-01
|
||||
-.1535646E-01 -.1714553E-01 -.1836106E-01 -.1893160E-01 -.1906335E-01
|
||||
-.1897772E-01 -.1879010E-01 -.1873646E-01 -.1877756E-01 -.1881406E-01
|
||||
-.1889539E-01 -.1903846E-01 -.1927963E-01 -.1956152E-01 -.1993420E-01
|
||||
-.2044804E-01 -.2097104E-01 -.2152963E-01 -.2210045E-01 -.2261029E-01
|
||||
-.2293475E-01 -.2269995E-01 -.2165200E-01 -.1990207E-01 -.1767281E-01
|
||||
-.1514958E-01 -.1254377E-01 -.9940813E-02 -.7251846E-02 -.4495867E-02
|
||||
-.1834558E-02 .3952551E-03 .1854653E-02 .2588015E-02 .2849055E-02
|
||||
.2815094E-02 .2756684E-02 .2919244E-02 .3275645E-02 .3764375E-02
|
||||
.4392082E-02 .5123506E-02 .5873642E-02 .6631104E-02 .7435058E-02
|
||||
.8256780E-02 .9132857E-02 .1018645E-01 .1134536E-01 .1254313E-01
|
||||
.1377035E-01 .1493849E-01 .1591571E-01 .1646537E-01 .1650017E-01
|
||||
.1607343E-01 .1528927E-01 .1435211E-01 .1338305E-01 .1244231E-01
|
||||
.1162597E-01 .1083991E-01 .9958939E-02 .9008164E-02 .7897419E-02
|
||||
.6446123E-02 .4474120E-02 .2036402E-02 -.5182785E-03 -.2859306E-02
|
||||
-.4600725E-02 -.5509272E-02 -.5738853E-02 -.5606866E-02 -.5408165E-02
|
||||
-.5262522E-02 -.5301959E-02 -.5500603E-02 -.5615600E-02 -.5664186E-02
|
||||
-.5684226E-02 -.5563378E-02 -.5416233E-02 -.5361794E-02 -.5286615E-02
|
||||
-.5222926E-02 -.5182292E-02 -.5049308E-02 -.4734245E-02 -.4146149E-02
|
||||
-.3186759E-02 -.1834258E-02 -.3142676E-03 .1142894E-02 .2213497E-02
|
||||
.2677973E-02 .2576888E-02 .2049605E-02 .1353403E-02 .6370208E-03
|
||||
.7696284E-04 -.3840222E-03 -.8431719E-03 -.1240350E-02 -.1731362E-02
|
||||
-.2287197E-02 -.2781299E-02 -.3341096E-02 -.3964879E-02 -.4680874E-02
|
||||
-.5636460E-02 -.6760819E-02 -.7853342E-02 -.8590249E-02 -.8662570E-02
|
||||
-.8005848E-02 -.6810741E-02 -.5326752E-02 -.3841953E-02 -.2599307E-02
|
||||
-.1789202E-02 -.1618141E-02 -.2135000E-02 -.3277990E-02 -.4839744E-02
|
||||
-.6556841E-02 -.8289200E-02 -.9959017E-02 -.1153790E-01 -.1306828E-01
|
||||
-.1444045E-01 -.1538276E-01 -.1571496E-01 -.1526215E-01 -.1412375E-01
|
||||
-.1262103E-01 -.1094714E-01 -.9336365E-02 -.7883712E-02 -.6546693E-02
|
||||
-.5324920E-02 -.4283892E-02 -.3511433E-02 -.3010718E-02 -.2758518E-02
|
||||
-.2689395E-02 -.2642917E-02 -.2503958E-02 -.2262002E-02 -.1930234E-02
|
||||
-.1526137E-02 -.1090235E-02 -.7078323E-03 -.2727131E-03 .3235799E-03
|
||||
.1020995E-02 .1760420E-02 .2252078E-02 .2182029E-02 .1537890E-02
|
||||
.3984516E-03 -.1015696E-02 -.2421581E-02 -.3720552E-02 -.4914779E-02
|
||||
-.6040551E-02 -.7089596E-02 -.8104178E-02 -.9080414E-02 -.9967503E-02
|
||||
-.1081311E-01 -.1162745E-01 -.1241252E-01 -.1318338E-01 -.1396752E-01
|
||||
-.1476899E-01 -.1556185E-01 -.1630489E-01 -.1681531E-01 -.1693400E-01
|
||||
-.1658796E-01 -.1570630E-01 -.1448131E-01 -.1311323E-01 -.1171250E-01
|
||||
-.1040772E-01 -.9136133E-02 -.7879401E-02 -.6630753E-02 -.5363429E-02
|
||||
-.4198113E-02 -.3202102E-02 -.2458119E-02 -.1994086E-02 -.1713913E-02
|
||||
-.1527896E-02 -.1312832E-02 -.1087912E-02 -.8321918E-03 -.5112643E-03
|
||||
-.2468145E-03 -.8340905E-05 .2647129E-03 .5213375E-03 .7621085E-03
|
||||
.1038711E-02 .1405533E-02 .1871109E-02 .2460456E-02 .3220863E-02
|
||||
.4082577E-02 .4985384E-02 .5953673E-02 .6965389E-02 .8070290E-02
|
||||
.9368096E-02 .1078513E-01 .1215192E-01 .1331484E-01 .1415191E-01
|
||||
.1469661E-01 .1507143E-01 .1535172E-01 .1564179E-01 .1603185E-01
|
||||
.1647825E-01 .1692019E-01 .1734562E-01 .1772421E-01 .1808961E-01
|
||||
.1845048E-01 .1882569E-01 .1927590E-01 .1973504E-01 .2018737E-01
|
||||
.2068158E-01 .2115884E-01 .2163320E-01 .2215990E-01 .2268229E-01
|
||||
.2321502E-01 .2379547E-01 .2440197E-01 .2507779E-01 .2581341E-01
|
||||
.2655814E-01 .2736368E-01 .2822543E-01 .2905153E-01 .2983108E-01
|
||||
.3059166E-01 .3114084E-01 .3131671E-01 .3111218E-01 .3051305E-01
|
||||
.2968909E-01 .2874523E-01 .2782100E-01 .2703444E-01 .2629805E-01
|
||||
.2572662E-01 .2539096E-01 .2512752E-01 .2493473E-01 .2488788E-01
|
||||
.2479736E-01 .2464927E-01 .2455270E-01 .2447592E-01 .2439927E-01
|
||||
.2430172E-01 .2426220E-01 .2426375E-01 .2427464E-01 .2437629E-01
|
||||
.2463915E-01 .2505681E-01 .2559246E-01 .2620214E-01 .2672332E-01
|
||||
.2697367E-01 .2674980E-01 .2590527E-01 .2449912E-01 .2270682E-01
|
||||
.2072397E-01 .1872458E-01 .1681497E-01 .1489248E-01 .1273290E-01
|
||||
.1014357E-01 .6973620E-02 .3233493E-02 -.9093364E-03 -.5091927E-02
|
||||
-.8996452E-02 -.1249101E-01 -.1546102E-01 -.1801931E-01 -.2037502E-01
|
||||
-.2256763E-01 -.2452619E-01 -.2615070E-01 -.2741391E-01 -.2833618E-01
|
||||
-.2901275E-01 -.2964300E-01 -.3027277E-01 -.3094581E-01 -.3169998E-01
|
||||
-.3237588E-01 -.3285102E-01 -.3302768E-01 -.3291384E-01 -.3256415E-01
|
||||
-.3206932E-01 -.3161216E-01 -.3117883E-01 -.3075836E-01 -.3038615E-01
|
||||
-.2997476E-01 -.2949072E-01 -.2889738E-01 -.2808077E-01 -.2703998E-01
|
||||
-.2581368E-01 -.2444338E-01 -.2305014E-01 -.2163020E-01 -.2024749E-01
|
||||
-.1895732E-01 -.1765319E-01 -.1636023E-01 -.1508094E-01 -.1385074E-01
|
||||
-.1283443E-01 -.1209795E-01 -.1174222E-01 -.1181543E-01 -.1213725E-01
|
||||
-.1254287E-01 -.1296419E-01 -.1333252E-01 -.1364070E-01 -.1391640E-01
|
||||
-.1419105E-01 -.1445969E-01 -.1465255E-01 -.1477652E-01 -.1483936E-01
|
||||
-.1483403E-01 -.1476891E-01 -.1473926E-01 -.1479601E-01 -.1485080E-01
|
||||
-.1496509E-01 -.1515630E-01 -.1534250E-01 -.1553761E-01 -.1575086E-01
|
||||
-.1592756E-01 -.1601255E-01 -.1584265E-01 -.1520028E-01 -.1407137E-01
|
||||
-.1244699E-01 -.1044820E-01 -.8386543E-02 -.6500234E-02 -.5004164E-02
|
||||
-.4060089E-02 -.3704259E-02 -.3819263E-02 -.4212448E-02 -.4642108E-02
|
||||
-.5014184E-02 -.5350055E-02 -.5604700E-02 -.5835293E-02 -.6090989E-02
|
||||
-.6358608E-02 -.6583542E-02 -.6632757E-02 -.6375431E-02 -.5748163E-02
|
||||
-.4755098E-02 -.3513255E-02 -.2183013E-02 -.8565018E-03 .3689066E-03
|
||||
.1507668E-02 .2576427E-02 .3463083E-02 .4132497E-02 .4564437E-02
|
||||
.4712152E-02 .4682966E-02 .4604270E-02 .4516317E-02 .4480989E-02
|
||||
.4495280E-02 .4500414E-02 .4520279E-02 .4620587E-02 .4786315E-02
|
||||
.5036992E-02 .5389506E-02 .5790761E-02 .6240889E-02 .6682114E-02
|
||||
.7070261E-02 .7449444E-02 .7773744E-02 .7943765E-02 .7919061E-02
|
||||
.7642944E-02 .7139513E-02 .6501349E-02 .5792756E-02 .5122678E-02
|
||||
.4503649E-02 .3894988E-02 .3361803E-02 .2997071E-02 .2824104E-02
|
||||
.2904937E-02 .3302560E-02 .3891336E-02 .4538610E-02 .5184030E-02
|
||||
.5764024E-02 .6297548E-02 .6799505E-02 .7280018E-02 .7721628E-02
|
||||
.8008869E-02 .8101727E-02 .7967058E-02 .7636067E-02 .7217181E-02
|
||||
.6756832E-02 .6330422E-02 .5956595E-02 .5598731E-02 .5237896E-02
|
||||
.4858647E-02 .4459606E-02 .4042886E-02 .3623913E-02 .3331852E-02
|
||||
.3272202E-02 .3539817E-02 .4259329E-02 .5275553E-02 .6439381E-02
|
||||
.7688936E-02 .8888779E-02 .1003329E-01 .1115511E-01 .1226569E-01
|
||||
.1334822E-01 .1433992E-01 .1512568E-01 .1551267E-01 .1551125E-01
|
||||
.1519386E-01 .1465298E-01 .1409188E-01 .1356510E-01 .1306618E-01
|
||||
.1262291E-01 .1220510E-01 .1181274E-01 .1171580E-01 .1216633E-01
|
||||
.1331303E-01 .1524950E-01 .1777597E-01 .2057265E-01 .2329719E-01
|
||||
.2556155E-01 .2701758E-01 .2752620E-01 .2721820E-01 .2634695E-01
|
||||
.2523897E-01 .2414605E-01 .2319065E-01 .2235554E-01 .2145555E-01
|
||||
.2050957E-01 .1959173E-01 .1862220E-01 .1762740E-01 .1667050E-01
|
||||
.1579438E-01 .1496501E-01 .1416144E-01 .1341079E-01 .1265789E-01
|
||||
.1192034E-01 .1123068E-01 .1052241E-01 .9780018E-02 .9066127E-02
|
||||
.8375003E-02 .7732417E-02 .7280988E-02 .7107634E-02 .7182783E-02
|
||||
.7523201E-02 .8096221E-02 .8686772E-02 .9260346E-02 .9837201E-02
|
||||
.1037292E-01 .1092720E-01 .1152604E-01 .1217660E-01 .1289584E-01
|
||||
.1365187E-01 .1441366E-01 .1516193E-01 .1588677E-01 .1661195E-01
|
||||
.1731763E-01 .1802403E-01 .1874635E-01 .1947141E-01 .2022626E-01
|
||||
.2098042E-01 .2171716E-01 .2234676E-01 .2272494E-01 .2278279E-01
|
||||
.2250204E-01 .2195459E-01 .2123772E-01 .2048330E-01 .1978113E-01
|
||||
.1911287E-01 .1846887E-01 .1780861E-01 .1710777E-01 .1637331E-01
|
||||
.1562000E-01 .1489020E-01 .1419427E-01 .1352737E-01 .1287828E-01
|
||||
.1223727E-01 .1160183E-01 .1098388E-01 .1035602E-01 .9736413E-02
|
||||
.9122191E-02 .8497272E-02 .7891950E-02 .7262543E-02 .6617015E-02
|
||||
.5915304E-02 .5094611E-02 .4203631E-02 .3212819E-02 .2149947E-02
|
||||
.1075717E-02 -.2298022E-04 -.1061169E-02 -.2113488E-02 -.3225617E-02
|
||||
-.4313436E-02 -.5379884E-02 -.6293834E-02 -.6921222E-02 -.7212701E-02
|
||||
-.7168815E-02 -.6906375E-02 -.6550293E-02 -.6189936E-02 -.5934755E-02
|
||||
-.5930713E-02 -.6242107E-02 -.6902787E-02 -.7896883E-02 -.9142266E-02
|
||||
-.1054151E-01 -.1194656E-01 -.1327986E-01 -.1458012E-01 -.1583052E-01
|
||||
-.1691642E-01 -.1787921E-01 -.1868030E-01 -.1925149E-01 -.1966988E-01
|
||||
-.1994674E-01 -.2009811E-01 -.2020098E-01 -.2034127E-01 -.2048578E-01
|
||||
-.2063758E-01 -.2081370E-01 -.2104213E-01 -.2142617E-01 -.2201315E-01
|
||||
-.2286919E-01 -.2394956E-01 -.2515655E-01 -.2643643E-01 -.2769093E-01
|
||||
-.2888396E-01 -.3001620E-01 -.3110532E-01 -.3219363E-01 -.3319893E-01
|
||||
-.3405916E-01 -.3485087E-01 -.3563057E-01 -.3637475E-01 -.3708807E-01
|
||||
-.3781649E-01 -.3847712E-01 -.3887727E-01 -.3890360E-01 -.3847836E-01
|
||||
-.3756977E-01 -.3635029E-01 -.3502873E-01 -.3377670E-01 -.3253980E-01
|
||||
-.3136170E-01 -.3024498E-01 -.2883484E-01 -.2709108E-01 -.2495759E-01
|
||||
-.2241910E-01 -.1970108E-01 -.1696696E-01 -.1436926E-01 -.1195755E-01
|
||||
-.9720910E-02 -.7672811E-02 -.5682905E-02 -.3770845E-02 -.2103646E-02
|
||||
-.7040582E-03 .3173436E-03 .9817477E-03 .1355928E-02 .1659764E-02
|
||||
.2080315E-02 .2497159E-02 .3016884E-02 .3572530E-02 .4154701E-02
|
||||
.4847182E-02 .5578421E-02 .6394113E-02 .7215470E-02 .8141736E-02
|
||||
.9062471E-02 .9886537E-02 .1083171E-01 .1185518E-01 .1291593E-01
|
||||
.1388871E-01 .1453616E-01 .1471435E-01 .1416915E-01 .1297304E-01
|
||||
.1145868E-01 .9819351E-02 .8270624E-02 .6834504E-02 .5599903E-02
|
||||
.4676519E-02 .3879176E-02 .3234140E-02 .2802702E-02 .2398671E-02
|
||||
.1986406E-02 .1559084E-02 .1090037E-02 .5775177E-03 -.3815822E-04
|
||||
-.8359094E-03 -.1788261E-02 -.2690521E-02 -.3636459E-02 -.4751917E-02
|
||||
-.5712509E-02 -.6594045E-02 -.7534314E-02 -.8285085E-02 -.8825090E-02
|
||||
-.9027546E-02 -.8920334E-02 -.8616465E-02 -.8209239E-02 -.7895718E-02
|
||||
-.7546820E-02 -.7155055E-02 -.6639884E-02 -.5760295E-02 -.4302479E-02
|
||||
-.2278525E-02 .1790444E-03 .2898006E-02 .5379946E-02 .7395191E-02
|
||||
.8695836E-02 .9344333E-02 .9681676E-02 .9732507E-02 .9837005E-02
|
||||
.1003824E-01 .1015341E-01 .1022496E-01 .1000068E-01 .9404290E-02
|
||||
.8718918E-02 .7965965E-02 .7139967E-02 .6447437E-02 .5798382E-02
|
||||
.5082355E-02 .4318732E-02 .3301407E-02 .1877672E-02 -.6846301E-04
|
||||
-.2643313E-02 -.5544712E-02 -.8370909E-02 -.1083761E-01 -.1271198E-01
|
||||
-.1399774E-01 -.1479195E-01 -.1529283E-01 -.1580039E-01 -.1647093E-01
|
||||
-.1724617E-01 -.1791320E-01 -.1835852E-01 -.1849898E-01 -.1815983E-01
|
||||
-.1740111E-01 -.1643913E-01 -.1535994E-01 -.1430412E-01 -.1336712E-01
|
||||
-.1246845E-01 -.1155704E-01 -.1060923E-01 -.9638327E-02 -.8656718E-02
|
||||
-.7666105E-02 -.6681173E-02 -.5752546E-02 -.4931658E-02 -.4272852E-02
|
||||
-.3870866E-02 -.3667222E-02 -.3617013E-02 -.3704612E-02 -.3770654E-02
|
||||
-.3718759E-02 -.3655301E-02 -.3411307E-02 -.2840159E-02 -.2206053E-02
|
||||
-.1487967E-02 -.6835307E-03 .9757925E-04 .8886143E-03 .1693404E-02
|
||||
.2446109E-02 .3161164E-02 .3980987E-02 .4809609E-02 .5431513E-02
|
||||
.5752881E-02 .5650435E-02 .5032142E-02 .3868185E-02 .2294582E-02
|
||||
.6196050E-03 -.9887878E-03 -.2556106E-02 -.4106610E-02 -.5691645E-02
|
||||
-.7332418E-02 -.8953705E-02 -.1059824E-01 -.1221766E-01 -.1360945E-01
|
||||
-.1459371E-01 -.1494915E-01 -.1461667E-01 -.1387553E-01 -.1285067E-01
|
||||
-.1172563E-01 -.1076229E-01 -.9815928E-02 -.8952319E-02 -.8155768E-02
|
||||
-.7227701E-02 -.6300747E-02 -.5377636E-02 -.4484430E-02 -.3589152E-02
|
||||
-.2671803E-02 -.1892406E-02 -.1054205E-02 -.1201819E-03 .7704291E-03
|
||||
.1632170E-02 .2526696E-02 .3426523E-02 .4181529E-02 .5044319E-02
|
||||
.5875677E-02 .6575618E-02 .7400322E-02 .8108606E-02 .8789829E-02
|
||||
.9514649E-02 .1006948E-01 .1036924E-01 .1035038E-01 .9992362E-02
|
||||
.9336564E-02 .8514637E-02 .7772245E-02 .7086018E-02 .6330743E-02
|
||||
.5802475E-02 .5285529E-02 .4688325E-02 .4336251E-02 .3978414E-02
|
||||
.3639463E-02 .3396644E-02 .3074477E-02 .2787161E-02 .2511388E-02
|
||||
.2205691E-02 .1943480E-02 .1667270E-02 .1387161E-02 .1148147E-02
|
||||
.8478166E-03 .5463956E-03 .3801887E-03 .1880852E-03 .1437325E-03
|
||||
.3579065E-03 .8096251E-03 .1510281E-02 .2254199E-02 .2947614E-02
|
||||
.3376264E-02 .3449274E-02 .2978388E-02 .1971365E-02 .8025815E-03
|
||||
-.4945727E-03 -.1777486E-02 -.2912057E-02 -.4025415E-02 -.5113880E-02
|
||||
-.6114851E-02 -.7037254E-02 -.7985605E-02 -.8774682E-02 -.9440006E-02
|
||||
-.1019836E-01 -.1088072E-01 -.1158510E-01 -.1238042E-01 -.1306384E-01
|
||||
-.1371476E-01 -.1448139E-01 -.1514874E-01 -.1575684E-01 -.1638967E-01
|
||||
-.1690445E-01 -.1741117E-01 -.1795520E-01 -.1848447E-01 -.1900292E-01
|
||||
-.1950628E-01 -.2005206E-01 -.2061885E-01 -.2107893E-01 -.2133895E-01
|
||||
-.2135737E-01 -.2100709E-01 -.2014016E-01 -.1895980E-01 -.1767444E-01
|
||||
-.1630400E-01 -.1495259E-01 -.1374251E-01 -.1251072E-01 -.1122870E-01
|
||||
-.1001319E-01 -.8738274E-02 -.7539443E-02 -.6492908E-02 -.5519300E-02
|
||||
-.4694943E-02 -.3970272E-02 -.3286336E-02 -.2520465E-02 -.1748277E-02
|
||||
-.1022217E-02 -.2091931E-03 .5724945E-03 .1327017E-02 .2074191E-02
|
||||
.2838011E-02 .3598866E-02 .4373636E-02 .5175845E-02 .5918087E-02
|
||||
.6690399E-02 .7514947E-02 .8289509E-02 .9013026E-02 .9841878E-02
|
||||
.1068634E-01 .1144395E-01 .1221876E-01 .1296432E-01 .1370129E-01
|
||||
.1444306E-01 .1513911E-01 .1589179E-01 .1667051E-01 .1740415E-01
|
||||
.1817201E-01 .1894096E-01 .1971361E-01 .2051700E-01 .2131862E-01
|
||||
.2205118E-01 .2274641E-01 .2343906E-01 .2407451E-01 .2470104E-01
|
||||
.2529072E-01 .2593011E-01 .2659463E-01 .2723364E-01 .2786906E-01
|
||||
.2848375E-01 .2910891E-01 .2963695E-01 .3000056E-01 .2995937E-01
|
||||
.2951968E-01 .2888872E-01 .2799730E-01 .2700131E-01 .2607613E-01
|
||||
.2520082E-01 .2433173E-01 .2355243E-01 .2275422E-01 .2179665E-01
|
||||
.2091438E-01 .2000954E-01 .1896054E-01 .1789333E-01 .1672851E-01
|
||||
.1553590E-01 .1438577E-01 .1315009E-01 .1191806E-01 .1073388E-01
|
||||
.9582577E-02 .8481141E-02 .7482894E-02 .6801505E-02 .6427535E-02
|
||||
.6316712E-02 .6416042E-02 .6511312E-02 .6613763E-02 .6761348E-02
|
||||
.6778063E-02 .6754865E-02 .6793810E-02 .6827682E-02 .6888210E-02
|
||||
.6916816E-02 .6950606E-02 .6981167E-02 .6993561E-02 .7042773E-02
|
||||
.7046740E-02 .7059720E-02 .7114555E-02 .7161510E-02 .7167308E-02
|
||||
.7021681E-02 .6649175E-02 .6064092E-02 .5291766E-02 .4406959E-02
|
||||
.3457435E-02 .2510584E-02 .1687596E-02 .9352894E-03 .3782349E-03
|
||||
.1257357E-03 .1212414E-03 .4098958E-03 .8233052E-03 .1250195E-02
|
||||
.1674710E-02 .2032924E-02 .2381777E-02 .2719313E-02 .3040589E-02
|
||||
.3340891E-02 .3516452E-02 .3454116E-02 .3134428E-02 .2638280E-02
|
||||
.1988043E-02 .1291571E-02 .6513633E-03 .4115712E-04 -.5110257E-03
|
||||
-.9729956E-03 -.1252806E-02 -.1283499E-02 -.1028184E-02 -.5427602E-03
|
||||
.9048501E-04 .8000865E-03 .1351701E-02 .1608437E-02 .1422218E-02
|
||||
.5642980E-03 -.8702073E-03 -.2665578E-02 -.4659463E-02 -.6645737E-02
|
||||
-.8581648E-02 -.1042527E-01 -.1223105E-01 -.1400749E-01 -.1562581E-01
|
||||
-.1694479E-01 -.1765803E-01 -.1777538E-01 -.1742752E-01 -.1671990E-01
|
||||
-.1593158E-01 -.1524717E-01 -.1464345E-01 -.1407914E-01 -.1355395E-01
|
||||
-.1296656E-01 -.1226515E-01 -.1148702E-01 -.1071789E-01 -.9963704E-02
|
||||
-.9108515E-02 -.8094684E-02 -.6900508E-02 -.5413114E-02 -.3639058E-02
|
||||
-.1773502E-02 .9424512E-04 .1962628E-02 .3710333E-02 .5243191E-02
|
||||
.6386772E-02 .6831027E-02 .6553389E-02 .5645105E-02 .4306550E-02
|
||||
.2871868E-02 .1525925E-02 .2722562E-03 -.8360054E-03 -.1739573E-02
|
||||
-.2460971E-02 -.2890240E-02 -.2975844E-02 -.2823912E-02 -.2576770E-02
|
||||
-.2300651E-02 -.2067811E-02 -.1898546E-02 -.1851372E-02 -.2084421E-02
|
||||
-.2579161E-02 -.3336360E-02 -.4353439E-02 -.5507340E-02 -.6728171E-02
|
||||
-.7971964E-02 -.9286932E-02 -.1077157E-01 -.1236036E-01 -.1379893E-01
|
||||
-.1478611E-01 -.1501493E-01 -.1427981E-01 -.1275392E-01 -.1087813E-01
|
||||
-.8980823E-02 -.7400696E-02 -.6455729E-02 -.6091517E-02 -.6098226E-02
|
||||
-.6289263E-02 -.6479012E-02 -.6536858E-02 -.6364211E-02 -.5797897E-02
|
||||
-.4745136E-02 -.3211062E-02 -.1275368E-02 .7720732E-03 .2704702E-02
|
||||
.4414194E-02 .5800065E-02 .6879298E-02 .7692018E-02 .8150432E-02
|
||||
.8205491E-02 .7975042E-02 .7542872E-02 .6995942E-02 .6475484E-02
|
||||
.5984036E-02 .5545801E-02 .5125410E-02 .4596901E-02 .3936358E-02
|
||||
.2992405E-02 .1756064E-02 .2768444E-03 -.1385962E-02 -.3060575E-02
|
||||
-.4692069E-02 -.6210452E-02 -.7548923E-02 -.8608174E-02 -.9324367E-02
|
||||
-.9743044E-02 -.9966012E-02 -.1007410E-01 -.1016823E-01 -.1032774E-01
|
||||
-.1048900E-01 -.1067007E-01 -.1086707E-01 -.1102498E-01 -.1116417E-01
|
||||
-.1130411E-01 -.1145015E-01 -.1156416E-01 -.1161813E-01 -.1151396E-01
|
||||
-.1116910E-01 -.1062412E-01 -.9873373E-02 -.8987641E-02 -.8123078E-02
|
||||
-.7252574E-02 -.6277929E-02 -.5139615E-02 -.3758278E-02 -.2108786E-02
|
||||
-.3037877E-03 .1512916E-02 .3246851E-02 .4825347E-02 .6165732E-02
|
||||
.7053946E-02 .7407015E-02 .7306948E-02 .6824108E-02 .6126497E-02
|
||||
.5395605E-02 .4735706E-02 .4145562E-02 .3582880E-02 .3010571E-02
|
||||
.2429016E-02 .1852722E-02 .1268032E-02 .7790853E-03 .4163089E-03
|
||||
.1241426E-03 -.8256823E-04 -.2676551E-03 -.4565719E-03 -.6765935E-03
|
||||
-.9578543E-03 -.1333950E-02 -.1929485E-02 -.2799383E-02 -.3998797E-02
|
||||
-.5411238E-02 -.6809948E-02 -.8094199E-02 -.9140870E-02 -.9939898E-02
|
||||
-.1059492E-01 -.1120225E-01 -.1184145E-01 -.1246029E-01 -.1296932E-01
|
||||
-.1328528E-01 -.1330266E-01 -.1300279E-01 -.1249487E-01 -.1195061E-01
|
||||
-.1142438E-01 -.1091830E-01 -.1046579E-01 -.1002865E-01 -.9516446E-02
|
||||
-.8880209E-02 -.8162702E-02 -.7381981E-02 -.6569535E-02 -.5844293E-02
|
||||
-.5332524E-02 -.5127164E-02 -.5230984E-02 -.5580506E-02 -.6065199E-02
|
||||
-.6576555E-02 -.7055518E-02 -.7483169E-02 -.7857245E-02 -.8210891E-02
|
||||
-.8549536E-02 -.8784769E-02 -.8908805E-02 -.8965009E-02 -.8953785E-02
|
||||
-.8890542E-02 -.8812452E-02 -.8770742E-02 -.8713877E-02 -.8496546E-02
|
||||
-.8073468E-02 -.7415896E-02 -.6556235E-02 -.5609972E-02 -.4620983E-02
|
||||
-.3651461E-02 -.2776462E-02 -.2047861E-02 -.1570904E-02 -.1433280E-02
|
||||
-.1627593E-02 -.2091562E-02 -.2670573E-02 -.3159750E-02 -.3295051E-02
|
||||
-.2841774E-02 -.1722596E-02 -.3081415E-04 .2012427E-02 .4195846E-02
|
||||
.7759243E-02 .1009041E-01 .1234082E-01 .1430464E-01 .1580129E-01
|
||||
.1664470E-01 .1683972E-01 .1664863E-01 .1637586E-01 .1633187E-01
|
||||
.1673473E-01 .1755643E-01 .1865395E-01 .1977178E-01 .2065249E-01
|
||||
.2119936E-01 .2144359E-01 .2154501E-01 .2162092E-01 .2175057E-01
|
||||
.2198130E-01 .2222906E-01 .2246085E-01 .2266158E-01 .2281945E-01
|
||||
.2299220E-01 .2326148E-01 .2368028E-01 .2424810E-01 .2493331E-01
|
||||
.2567153E-01 .2640765E-01 .2709228E-01 .2770083E-01 .2828892E-01
|
||||
.2888795E-01 .2944563E-01 .2997140E-01 .3044045E-01 .3067170E-01
|
||||
.3057340E-01 .3011340E-01 .2927922E-01 .2827632E-01 .2726479E-01
|
||||
.2618787E-01 .2508466E-01 .2394896E-01 .2263012E-01 .2115497E-01
|
||||
.1961779E-01 .1812645E-01 .1682319E-01 .1590214E-01 .1546219E-01
|
||||
.1538958E-01 .1553484E-01 .1573604E-01 .1587445E-01 .1580009E-01
|
||||
.1544133E-01 .1481476E-01 .1392805E-01 .1286946E-01 .1175946E-01
|
||||
.1068899E-01 .9637313E-02 .8571257E-02 .7508245E-02 .6396172E-02
|
||||
.5176293E-02 .3871487E-02 .2513818E-02 .1133142E-02 -.2125730E-03
|
||||
-.1472745E-02 -.2621101E-02 -.3570533E-02 -.4262023E-02 -.4737111E-02
|
||||
-.5092072E-02 -.5395414E-02 -.5679843E-02 -.6017004E-02 -.6386026E-02
|
||||
-.6787382E-02 -.7300432E-02 -.7967211E-02 -.8808489E-02 -.9845551E-02
|
||||
-.1098767E-01 -.1203648E-01 -.1285782E-01 -.1330239E-01 -.1328962E-01
|
||||
-.1295417E-01 -.1244764E-01 -.1186071E-01 -.1131595E-01 -.1089068E-01
|
||||
-.1059892E-01 -.1049736E-01 -.1060687E-01 -.1094933E-01 -.1152811E-01
|
||||
-.1220358E-01 -.1289204E-01 -.1357616E-01 -.1423100E-01 -.1482947E-01
|
||||
-.1538425E-01 -.1592233E-01 -.1636338E-01 -.1656591E-01 -.1643236E-01
|
||||
-.1597662E-01 -.1527350E-01 -.1443529E-01 -.1357836E-01 -.1278392E-01
|
||||
-.1206561E-01 -.1137277E-01 -.1071076E-01 -.1017280E-01 -.9799921E-02
|
||||
-.9649394E-02 -.9757075E-02 -.1004074E-01 -.1042480E-01 -.1079276E-01
|
||||
-.1109372E-01 -.1136999E-01 -.1160094E-01 -.1178761E-01 -.1197894E-01
|
||||
-.1207333E-01 -.1193329E-01 -.1155171E-01 -.1093361E-01 -.1012867E-01
|
||||
-.9261098E-02 -.8423422E-02 -.7678327E-02 -.7119483E-02 -.6791939E-02
|
||||
-.6712115E-02 -.6843079E-02 -.7089660E-02 -.7379934E-02 -.7649899E-02
|
||||
-.7845475E-02 -.7915957E-02 -.7819283E-02 -.7499915E-02 -.6994798E-02
|
||||
-.6395132E-02 -.5723564E-02 -.5048186E-02 -.4439030E-02 -.3859009E-02
|
||||
-.3285826E-02 -.2720984E-02 -.2147649E-02 -.1564056E-02 -.9720655E-03
|
||||
-.3924482E-03 .1650661E-03 .7174124E-03 .1257095E-02 .1789369E-02
|
||||
.2359872E-02 .2957085E-02 .3528682E-02 .4030079E-02 .4409755E-02
|
||||
.4610036E-02 .4614296E-02 .4491448E-02 .4327655E-02 .4181567E-02
|
||||
.4104591E-02 .4130779E-02 .4265152E-02 .4465588E-02 .4693861E-02
|
||||
.4931583E-02 .5140223E-02 .5326284E-02 .5517676E-02 .5702954E-02
|
||||
.5880905E-02 .6067302E-02 .6213250E-02 .6267491E-02 .6210680E-02
|
||||
.6029982E-02 .5763171E-02 .5463723E-02 .5173041E-02 .4898239E-02
|
||||
.4639396E-02 .4397928E-02 .4151844E-02 .3904857E-02 .3663023E-02
|
||||
.3445871E-02 .3303808E-02 .3251068E-02 .3289394E-02 .3397992E-02
|
||||
.3510975E-02 .3548474E-02 .3458961E-02 .3214734E-02 .2803493E-02
|
||||
.2291440E-02 .1774944E-02 .1277190E-02 .7986186E-03 .3663494E-03
|
||||
-.3482560E-04 -.4354777E-03 -.8270837E-03 -.1209550E-02 -.1576519E-02
|
||||
-.1914450E-02 -.2243036E-02 -.2553874E-02 -.2851191E-02 -.3150080E-02
|
||||
-.3432364E-02 -.3706000E-02 -.3985497E-02 -.4265150E-02 -.4527991E-02
|
||||
-.4767252E-02 -.4964962E-02 -.5061370E-02 -.5023966E-02 -.4868896E-02
|
||||
-.4625376E-02 -.4352955E-02 -.4107218E-02 -.3938803E-02 -.3873476E-02
|
||||
-.3905834E-02 -.4019462E-02 -.4164923E-02 -.4317415E-02 -.4467577E-02
|
||||
-.4621323E-02 -.4794882E-02 -.4987393E-02 -.5198910E-02 -.5387553E-02
|
||||
-.5502042E-02 -.5509470E-02 -.5372261E-02 -.5121201E-02 -.4810435E-02
|
||||
-.4475207E-02 -.4173282E-02 -.3924784E-02 -.3747185E-02 -.3661682E-02
|
||||
-.3644232E-02 -.3678184E-02 -.3736803E-02 -.3780249E-02 -.3787912E-02
|
||||
-.3723627E-02 -.3553096E-02 -.3274377E-02 -.2914601E-02 -.2510209E-02
|
||||
-.2101883E-02 -.1725180E-02 -.1395088E-02 -.1110167E-02 -.8630921E-03
|
||||
-.6677471E-03 -.5430111E-03 -.4917591E-03 -.5032961E-03 -.5512626E-03
|
||||
-.6093181E-03 -.6585218E-03 -.6917868E-03 -.7160987E-03 -.7341155E-03
|
||||
-.7577296E-03 -.7942437E-03 -.8357234E-03 -.8798277E-03 -.9201046E-03
|
||||
-.9494655E-03 -.9693090E-03 -.9821635E-03 -.9870876E-03 -.9832932E-03
|
||||
-.9688699E-03 -.9330460E-03 -.8579200E-03 -.7386728E-03 -.5812859E-03
|
||||
-.3997294E-03 -.2121420E-03 -.3243040E-04 .1293954E-03 .2772012E-03
|
||||
.4166618E-03 .5497497E-03 .6796009E-03 .8076697E-03 .9376777E-03
|
||||
.1074204E-02 .1216486E-02 .1357106E-02 .1494193E-02 .1621883E-02
|
||||
.1732130E-02 .1829667E-02 .1911760E-02 .1975442E-02 .2025713E-02
|
||||
.2061568E-02 .2084805E-02 .2099837E-02 .2107158E-02 .2109271E-02
|
||||
.2105125E-02 .2094110E-02 .2077210E-02 .2051453E-02 .2012648E-02
|
||||
.1957224E-02 .1882890E-02 .1792851E-02 .1696231E-02 .1598098E-02
|
||||
.1503724E-02 .1416341E-02 .1333911E-02 .1256371E-02 .1182076E-02
|
||||
.1109747E-02 .1040603E-02 .9743627E-03 .9119862E-03 .8541323E-03
|
||||
.7998095E-03 .7486704E-03 .7007959E-03 .6561052E-03 .6137506E-03
|
||||
.5743657E-03 .5383776E-03 .5055391E-03 .4752999E-03 .4477320E-03
|
||||
.4230737E-03 .4005037E-03 .3795673E-03 .3579860E-03 .3348679E-03
|
||||
.3105352E-03 .2860160E-03 .2652565E-03 .2503434E-03 .2422912E-03
|
||||
.2417031E-03 .2476960E-03 .2604719E-03 .2802572E-03 .3068705E-03
|
||||
.3386556E-03 .3722990E-03 .4052977E-03 .4356823E-03 .4622546E-03
|
||||
.4852438E-03 .5057260E-03 .5246352E-03 .5425639E-03 .5599601E-03
|
||||
.5767023E-03 .5925052E-03 .6072328E-03 .6208209E-03 .6330554E-03
|
||||
.6435786E-03 .6521876E-03 .6587709E-03 .6634079E-03 .6663115E-03
|
||||
.6677464E-03 .6680027E-03 .6673014E-03 .6658006E-03 .6636009E-03
|
||||
144
examples/data/EigenAnal_twoStoreyFrame1.tcl.txt
Normal file
144
examples/data/EigenAnal_twoStoreyFrame1.tcl.txt
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# Eigen analysis of a two-storey one-bay frame; Example 10.5 from "Dynamics of Structures" book by Anil Chopra
|
||||
|
||||
# units: kips, in, sec
|
||||
|
||||
# Vesna Terzic, 2010
|
||||
|
||||
#delete all previosly constructed objects
|
||||
wipe;
|
||||
|
||||
#set input variables
|
||||
#--------------------
|
||||
|
||||
#mass
|
||||
set m [expr 100.0/386.0]
|
||||
|
||||
#number of modes
|
||||
set numModes 2
|
||||
|
||||
#material
|
||||
set A 63.41
|
||||
set I 320.0
|
||||
set E 29000.0
|
||||
|
||||
#geometry
|
||||
set L 240.
|
||||
set h 120.
|
||||
|
||||
# create data directory
|
||||
file mkdir modes;
|
||||
|
||||
# define the model
|
||||
#---------------------------------
|
||||
#model builder
|
||||
model BasicBuilder -ndm 2 -ndf 3
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0. 0. ;
|
||||
node 2 $L 0. ;
|
||||
node 3 0. $h ;
|
||||
node 4 $L $h ;
|
||||
node 5 0. [expr 2*$h];
|
||||
node 6 $L [expr 2*$h];
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1;
|
||||
fix 2 1 1 1;
|
||||
|
||||
# assign mass
|
||||
mass 3 $m 0. 0. ;
|
||||
mass 4 $m 0. 0. ;
|
||||
mass 5 [expr $m/2.] 0. 0. ;
|
||||
mass 6 [expr $m/2.] 0. 0. ;
|
||||
|
||||
# define geometric transformation:
|
||||
set TransfTag 1;
|
||||
geomTransf Linear $TransfTag ;
|
||||
|
||||
# define elements:
|
||||
# columns
|
||||
element elasticBeamColumn 1 1 3 $A $E [expr 2.*$I] $TransfTag;
|
||||
element elasticBeamColumn 2 3 5 $A $E $I $TransfTag;
|
||||
element elasticBeamColumn 3 2 4 $A $E [expr 2.*$I] $TransfTag;
|
||||
element elasticBeamColumn 4 4 6 $A $E $I $TransfTag;
|
||||
# beams
|
||||
element elasticBeamColumn 5 3 4 $A $E [expr 2.*$I] $TransfTag;
|
||||
element elasticBeamColumn 6 5 6 $A $E $I $TransfTag;
|
||||
|
||||
# record eigenvectors
|
||||
#----------------------
|
||||
for { set k 1 } { $k <= $numModes } { incr k } {
|
||||
recorder Node -file [format "modes/mode%i.out" $k] -nodeRange 1 6 -dof 1 2 3 "eigen $k"
|
||||
}
|
||||
|
||||
# perform eigen analysis
|
||||
#-----------------------------
|
||||
set lambda [eigen $numModes];
|
||||
|
||||
# calculate frequencies and periods of the structure
|
||||
#---------------------------------------------------
|
||||
set omega {}
|
||||
set f {}
|
||||
set T {}
|
||||
set pi 3.141593
|
||||
|
||||
foreach lam $lambda {
|
||||
lappend omega [expr sqrt($lam)]
|
||||
lappend f [expr sqrt($lam)/(2*$pi)]
|
||||
lappend T [expr (2*$pi)/sqrt($lam)]
|
||||
}
|
||||
|
||||
puts "periods are $T"
|
||||
|
||||
# write the output file cosisting of periods
|
||||
#--------------------------------------------
|
||||
set period "modes/Periods.txt"
|
||||
set Periods [open $period "w"]
|
||||
foreach t $T {
|
||||
puts $Periods " $t"
|
||||
}
|
||||
close $Periods
|
||||
|
||||
# record the eigenvectors
|
||||
#------------------------
|
||||
record
|
||||
|
||||
# create display for mode shapes
|
||||
#---------------------------------
|
||||
# $windowTitle $xLoc $yLoc $xPixels $yPixels
|
||||
recorder display "Mode Shape 1" 10 10 500 500 -wipe
|
||||
prp $h $h 1; # projection reference point (prp); defines the center of projection (viewer eye)
|
||||
vup 0 1 0; # view-up vector (vup)
|
||||
vpn 0 0 1; # view-plane normal (vpn)
|
||||
viewWindow -200 200 -200 200; # coordiantes of the window relative to prp
|
||||
display -1 5 20; # the 1st arg. is the tag for display mode (ex. -1 is for the first mode shape)
|
||||
# the 2nd arg. is magnification factor for nodes, the 3rd arg. is magnif. factor of deformed shape
|
||||
recorder display "Mode Shape 2" 10 510 500 500 -wipe
|
||||
prp $h $h 1;
|
||||
vup 0 1 0;
|
||||
vpn 0 0 1;
|
||||
viewWindow -200 200 -200 200
|
||||
display -2 5 20
|
||||
|
||||
# get values of eigenvectors for translational DOFs
|
||||
#---------------------------------------------------
|
||||
set f11 [nodeEigenvector 3 1 1]
|
||||
set f21 [nodeEigenvector 5 1 1]
|
||||
set f12 [nodeEigenvector 3 2 1]
|
||||
set f22 [nodeEigenvector 5 2 1]
|
||||
puts "eigenvector 1: [list [expr {$f11/$f21}] [expr {$f21/$f21}] ]"
|
||||
puts "eigenvector 2: [list [expr {$f12/$f22}] [expr {$f22/$f22}] ]"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
167
examples/data/EigenAnal_twoStoreyShearFrame7.tcl.txt
Normal file
167
examples/data/EigenAnal_twoStoreyShearFrame7.tcl.txt
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# Eigen analysis of a two-storey shear frame; Example 10.4 from "Dynamics of Structures" book by Anil Chopra - using equalDOF and very high Ib
|
||||
|
||||
# units: in, kips
|
||||
|
||||
wipe
|
||||
|
||||
#input
|
||||
set m [expr 100.0/386.0]
|
||||
set numModes 2
|
||||
|
||||
#material
|
||||
set Ac 63.41
|
||||
set Ic 320.0
|
||||
set E 30000.0
|
||||
set Ib 10e+12
|
||||
set Ab 63.41
|
||||
|
||||
#geometry
|
||||
set L 288.
|
||||
set h 144.
|
||||
|
||||
# create data directory
|
||||
file mkdir modes;
|
||||
|
||||
# define the model
|
||||
#---------------------------------
|
||||
#model builder
|
||||
model BasicBuilder -ndm 2 -ndf 3
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0. 0. ;
|
||||
node 2 $L 0. ;
|
||||
node 3 0. $h ;
|
||||
node 4 $L $h ;
|
||||
node 5 0. [expr 2*$h];
|
||||
node 6 $L [expr 2*$h];
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1;
|
||||
fix 2 1 1 1;
|
||||
|
||||
# MP constraints
|
||||
equalDOF 3 4 2 3
|
||||
equalDOF 5 6 2 3
|
||||
|
||||
# assign mass
|
||||
mass 3 $m 0. 0. ;
|
||||
mass 4 $m 0. 0. ;
|
||||
mass 5 [expr $m/2.] 0. 0. ;
|
||||
mass 6 [expr $m/2.] 0. 0. ;
|
||||
|
||||
# define geometric transformation:
|
||||
set TransfTag 1;
|
||||
geomTransf Linear $TransfTag ;
|
||||
|
||||
# define elements:
|
||||
# columns
|
||||
element elasticBeamColumn 1 1 3 $Ac $E [expr 2.*$Ic] $TransfTag;
|
||||
element elasticBeamColumn 2 3 5 $Ac $E $Ic $TransfTag;
|
||||
element elasticBeamColumn 3 2 4 $Ac $E [expr 2.*$Ic] $TransfTag;
|
||||
element elasticBeamColumn 4 4 6 $Ac $E $Ic $TransfTag;
|
||||
# beams
|
||||
element elasticBeamColumn 5 3 4 $Ab $E $Ib $TransfTag;
|
||||
element elasticBeamColumn 6 5 6 $Ab $E $Ib $TransfTag;
|
||||
|
||||
# record eigenvectors
|
||||
#----------------------
|
||||
for { set k 1 } { $k <= $numModes } { incr k } {
|
||||
recorder Node -file [format "modes/mode%i.out" $k] -nodeRange 1 6 -dof 1 2 3 "eigen $k"
|
||||
}
|
||||
|
||||
# perform eigen analysis
|
||||
#-----------------------------
|
||||
set lambda [eigen $numModes];
|
||||
|
||||
# calculate frequencies and periods of the structure
|
||||
#---------------------------------------------------
|
||||
set omega {}
|
||||
set f {}
|
||||
set T {}
|
||||
set pi 3.141593
|
||||
|
||||
foreach lam $lambda {
|
||||
lappend omega [expr sqrt($lam)]
|
||||
lappend f [expr sqrt($lam)/(2*$pi)]
|
||||
lappend T [expr (2*$pi)/sqrt($lam)]
|
||||
}
|
||||
|
||||
puts "periods are $T"
|
||||
|
||||
# write the output file cosisting of periods
|
||||
#--------------------------------------------
|
||||
set period "modes/Periods.txt"
|
||||
set Periods [open $period "w"]
|
||||
foreach t $T {
|
||||
puts $Periods " $t"
|
||||
}
|
||||
close $Periods
|
||||
|
||||
|
||||
# create display for mode shapes
|
||||
#---------------------------------
|
||||
# $windowTitle $xLoc $yLoc $xPixels $yPixels
|
||||
recorder display "Mode Shape 1" 10 10 500 500 -wipe
|
||||
prp $h $h 1; # projection reference point (prp); defines the center of projection (viewer eye)
|
||||
vup 0 1 0; # view-up vector (vup)
|
||||
vpn 0 0 1; # view-plane normal (vpn)
|
||||
viewWindow -200 200 -200 200; # coordiantes of the window relative to prp
|
||||
display -1 5 20; # the 1st arg. is the tag for display mode (ex. -1 is for the first mode shape)
|
||||
# the 2nd arg. is magnification factor for nodes, the 3rd arg. is magnif. factor of deformed shape
|
||||
recorder display "Mode Shape 2" 10 510 500 500 -wipe
|
||||
prp $h $h 1;
|
||||
vup 0 1 0;
|
||||
vpn 0 0 1;
|
||||
viewWindow -200 200 -200 200
|
||||
display -2 5 20
|
||||
|
||||
|
||||
# Run a one step gravity load with no loading (to record eigenvectors)
|
||||
#-----------------------------------------------------------------------
|
||||
integrator LoadControl 0 1 0 0
|
||||
|
||||
# Convergence test
|
||||
# tolerance maxIter displayCode
|
||||
test EnergyIncr 1.0e-10 100 0
|
||||
|
||||
# Solution algorithm
|
||||
algorithm Newton
|
||||
|
||||
# DOF numberer
|
||||
numberer RCM
|
||||
|
||||
# Constraint handler
|
||||
constraints Transformation
|
||||
|
||||
|
||||
# System of equations solver
|
||||
system ProfileSPD
|
||||
|
||||
analysis Static
|
||||
set res [analyze 1]
|
||||
if {$res < 0} {
|
||||
puts "Modal analysis failed"
|
||||
}
|
||||
|
||||
# get values of eigenvectors for translational DOFs
|
||||
#---------------------------------------------------
|
||||
set f11 [nodeEigenvector 3 1 1]
|
||||
set f21 [nodeEigenvector 5 1 1]
|
||||
set f12 [nodeEigenvector 3 2 1]
|
||||
set f22 [nodeEigenvector 5 2 1]
|
||||
puts "eigenvector 1: [list [expr {$f11/$f21}] [expr {$f21/$f21}] ]"
|
||||
puts "eigenvector 2: [list [expr {$f12/$f22}] [expr {$f22/$f22}] ]"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
95
examples/data/Ex1a.Canti2D.EQ.modif.tcl.txt
Normal file
95
examples/data/Ex1a.Canti2D.EQ.modif.tcl.txt
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 1. cantilever 2D
|
||||
# EQ ground motion with gravity
|
||||
# all units are in kip, inch, second
|
||||
# elasticBeamColumn ELEMENT
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) 36'
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= ---- -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear opensees model
|
||||
model basic -ndm 2 -ndf 3; # 2 dimensions, 3 dof per node
|
||||
file mkdir data; # create data directory
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
# nodal coordinates:
|
||||
node 1 0. 0.; # node#, X Y
|
||||
node 2 0. 432.
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 5.18 0. 0.; # node#, Mx My Mz, Mass=Weight/g.
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
geomTransf Linear 1; # associate a tag to transformation
|
||||
|
||||
# connectivity:
|
||||
element elasticBeamColumn 1 1 2 3600 3225 1080000 1; # element elasticBeamColumn $eleTag $iNode $jNode $A $E $Iz $transfTag
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 force; # element forces -- column
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
timeSeries Linear 1
|
||||
pattern Plain 1 1 {
|
||||
load 2 0. -2000. 0.; # node#, FX FY MZ -- superstructure-weight
|
||||
}
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
algorithm Linear; # use Linear algorithm for linear analysis
|
||||
integrator LoadControl 0.1; # determine the next time step for an analysis, # apply gravity in 10 steps
|
||||
analysis Static # define type of analysis static or transient
|
||||
analyze 10; # perform gravity analysis
|
||||
loadConst -time 0.0; # hold gravity constant and restart time
|
||||
|
||||
# DYNAMIC ground-motion analysis -------------------------------------------------------------
|
||||
# create load pattern
|
||||
set G 386
|
||||
timeSeries Path 2 -dt 0.005 -filePath A10000.tcl -factor $G; # define acceleration vector from file (dt=0.005 is associated with the input file gm)
|
||||
pattern UniformExcitation 2 1 -accel 2; # define where and how (pattern tag, dof) acceleration is applied
|
||||
|
||||
# set damping based on first eigen mode
|
||||
set freq [expr [eigen -fullGenLapack 1]**0.5]
|
||||
set dampRatio 0.02
|
||||
rayleigh 0. 0. 0. [expr 2*$dampRatio/$freq]
|
||||
|
||||
# display displacement shape of the column
|
||||
recorder display "Displaced shape" 10 10 500 500 -wipe
|
||||
prp 200. 50. 1;
|
||||
vup 0 1 0;
|
||||
vpn 0 0 1;
|
||||
display 1 5 40
|
||||
|
||||
# create the analysis
|
||||
wipeAnalysis; # clear previously-define analysis parameters
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
algorithm Linear # use Linear algorithm for linear analysis
|
||||
integrator Newmark 0.5 0.25 ; # determine the next time step for an analysis
|
||||
analysis Transient; # define type of analysis: time-dependent
|
||||
analyze 3995 0.01; # apply 3995 0.01-sec time steps in analysis
|
||||
|
||||
|
||||
puts "Done!"
|
||||
wipe
|
||||
|
||||
86
examples/data/Ex1a.Canti2D.EQ.tcl.txt
Normal file
86
examples/data/Ex1a.Canti2D.EQ.tcl.txt
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 1. cantilever 2D
|
||||
# EQ ground motion with gravity
|
||||
# all units are in kip, inch, second
|
||||
# elasticBeamColumn ELEMENT
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) 36'
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= ---- -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear opensees model
|
||||
model basic -ndm 2 -ndf 3; # 2 dimensions, 3 dof per node
|
||||
file mkdir Data; # create data directory
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X Y
|
||||
node 2 0 432
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 5.18 1.e-9 0.; # node#, Mx My Mz, Mass=Weight/g.
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
geomTransf Linear 1; # associate a tag to transformation
|
||||
|
||||
# connectivity: (make A very large, 10e6 times its actual value)
|
||||
element elasticBeamColumn 1 1 2 3600000000 4227 1080000 1; # element elasticBeamColumn $eleTag $iNode $jNode $A $E $Iz $transfTag
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 globalForce; # element forces -- column
|
||||
recorder Element -file Data/DCol.out -time -ele 1 deformations; # element deformations -- column
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0. -2000. 0.; # node#, FX FY MZ -- superstructure-weight
|
||||
}
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr 1.0e-8 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
integrator LoadControl 0.1; # determine the next time step for an analysis, # apply gravity in 10 steps
|
||||
analysis Static # define type of analysis static or transient
|
||||
analyze 10; # perform gravity analysis
|
||||
loadConst -time 0.0; # hold gravity constant and restart time
|
||||
|
||||
# DYNAMIC ground-motion analysis -------------------------------------------------------------
|
||||
# create load pattern
|
||||
set accelSeries "Series -dt 0.01 -filePath BM68elc.acc -factor 1"; # define acceleration vector from file (dt=0.01 is associated with the input file gm)
|
||||
pattern UniformExcitation 2 1 -accel $accelSeries; # define where and how (pattern tag, dof) acceleration is applied
|
||||
rayleigh 0. 0. 0. [expr 2*0.02/pow([eigen 1],0.5)]; # set damping based on first eigen mode
|
||||
|
||||
# create the analysis
|
||||
wipeAnalysis; # clear previously-define analysis parameters
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr 1.0e-8 10; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
integrator Newmark 0.5 0.25 ; # determine the next time step for an analysis
|
||||
analysis Transient; # define type of analysis: time-dependent
|
||||
analyze 1000 0.02; # apply 1000 0.02-sec time steps in analysis
|
||||
|
||||
|
||||
puts "Done!"
|
||||
|
||||
|
||||
80
examples/data/Ex1a.Canti2D.Push.tcl.txt
Normal file
80
examples/data/Ex1a.Canti2D.Push.tcl.txt
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 1. cantilever 2D
|
||||
# static pushover analysis with gravity.
|
||||
# all units are in kip, inch, second
|
||||
# elasticBeamColumn ELEMENT
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) 36'
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= ---- -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear opensees model
|
||||
model basic -ndm 2 -ndf 3; # 2 dimensions, 3 dof per node
|
||||
file mkdir Data; # create data directory
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X Y
|
||||
node 2 0 432
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 5.18 0. 0.; # node#, Mx My Mz, Mass=Weight/g.
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
geomTransf Linear 1; # associate a tag to transformation
|
||||
|
||||
# connectivity: (make A very large, 10e6 times its actual value)
|
||||
element elasticBeamColumn 1 1 2 3600000000 4227 1080000 1; # element elasticBeamColumn $eleTag $iNode $jNode $A $E $Iz $transfTag
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 globalForce; # element forces -- column
|
||||
recorder Element -file Data/DCol.out -time -ele 1 deformation; # element deformations -- column
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0. -2000. 0.; # node#, FX FY MZ -- superstructure-weight
|
||||
}
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr 1.0e-8 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
integrator LoadControl 0.1; # determine the next time step for an analysis, # apply gravity in 10 steps
|
||||
analysis Static # define type of analysis static or transient
|
||||
analyze 10; # perform gravity analysis
|
||||
loadConst -time 0.0; # hold gravity constant and restart time
|
||||
|
||||
# define LATERAL load -------------------------------------------------------------
|
||||
# Lateral load pattern
|
||||
pattern Plain 2 Linear {
|
||||
load 2 2000. 0.0 0.0; # node#, FX FY MZ -- representative lateral load at top node
|
||||
}
|
||||
|
||||
# pushover: diplacement controlled static analysis
|
||||
integrator DisplacementControl 2 1 0.1; # switch to displacement control, for node 11, dof 1, 0.1 increment
|
||||
analyze 1000; # apply 100 steps of pushover analysis to a displacement of 10
|
||||
|
||||
puts "Done!"
|
||||
|
||||
|
||||
|
||||
|
||||
95
examples/data/Ex1b.Portal2D.EQ.tcl.txt
Normal file
95
examples/data/Ex1b.Portal2D.EQ.tcl.txt
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 1. portal frame in 2D
|
||||
# dynamic earthquake analysis of Portal Frame, with gravity.
|
||||
# all units are in kip, inch, second
|
||||
# elasticBeamColumn ELEMENT
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 3_________(3)________4 __
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# (1) (2) LCol
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# =1= =2= _|_ -------->X
|
||||
# |----------LBeam------------|
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear opensees model
|
||||
model basic -ndm 2 -ndf 3; # 2 dimensions, 3 dof per node
|
||||
file mkdir Data; # create data directory
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X Y
|
||||
node 2 504 0
|
||||
node 3 0 432
|
||||
node 4 504 432
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
fix 2 1 1 1; # node DX DY RZ
|
||||
fix 3 0 0 0
|
||||
fix 4 0 0 0
|
||||
|
||||
# nodal masses:
|
||||
mass 3 5.18 0. 0.; # node#, Mx My Mz, Mass=Weight/g.
|
||||
mass 4 5.18 0. 0.
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
geomTransf Linear 1; # associate a tag to transformation
|
||||
|
||||
# connectivity: (make A very large, 10e6 times its actual value)
|
||||
element elasticBeamColumn 1 1 3 3600000000 4227 1080000 1; # element elasticBeamColumn $eleTag $iNode $jNode $A $E $Iz $transfTag
|
||||
element elasticBeamColumn 2 2 4 3600000000 4227 1080000 1
|
||||
element elasticBeamColumn 3 3 4 5760000000 4227 4423680 1
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 3 4 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 2 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 2 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 2 -jNode 3 4 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 2 globalForce; # element forces -- column
|
||||
recorder Element -file Data/FBeam.out -time -ele 3 globalForce; # element forces -- beam
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
eleLoad -ele 3 -type -beamUniform -7.94 ; # distributed superstructure-weight on beam
|
||||
}
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr 1.0e-8 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
integrator LoadControl 0.1; # determine the next time step for an analysis, # apply gravity in 10 steps
|
||||
analysis Static # define type of analysis static or transient
|
||||
analyze 10; # perform gravity analysis
|
||||
loadConst -time 0.0; # hold gravity constant and restart time
|
||||
|
||||
# DYNAMIC ground-motion analysis -------------------------------------------------------------
|
||||
# create load pattern
|
||||
set accelSeries "Series -dt 0.01 -filePath BM68elc.acc -factor 1"; # define acceleration vector from file (dt=0.01 is associated with the input file gm)
|
||||
pattern UniformExcitation 2 1 -accel $accelSeries; # define where and how (pattern tag, dof) acceleration is applied
|
||||
rayleigh 0. 0. 0. [expr 2*0.02/pow([eigen 1],0.5)]; # set damping based on first eigen mode
|
||||
|
||||
# create the analysis
|
||||
wipeAnalysis; # clear previously-define analysis parameters
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr 1.0e-8 10; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
integrator Newmark 0.5 0.25 ; # determine the next time step for an analysis
|
||||
analysis Transient; # define type of analysis: time-dependent
|
||||
analyze 1000 0.02; # apply 1000 0.02-sec time steps in analysis
|
||||
|
||||
|
||||
puts "Done!"
|
||||
|
||||
|
||||
94
examples/data/Ex1b.Portal2D.Push.tcl.txt
Normal file
94
examples/data/Ex1b.Portal2D.Push.tcl.txt
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 1. portal frame in 2D
|
||||
# static pushover analysis of Portal Frame, with gravity.
|
||||
# all units are in kip, inch, second
|
||||
# elasticBeamColumn ELEMENT
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 3_________(3)________4 __
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# (1) (2) LCol
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# =1= =2= _|_ -------->X
|
||||
# |----------LBeam------------|
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear opensees model
|
||||
model basic -ndm 2 -ndf 3; # 2 dimensions, 3 dof per node
|
||||
file mkdir Data; # create data directory
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X Y
|
||||
node 2 504 0
|
||||
node 3 0 432
|
||||
node 4 504 432
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
fix 2 1 1 1; # node DX DY RZ
|
||||
fix 3 0 0 0
|
||||
fix 4 0 0 0
|
||||
|
||||
# nodal masses:
|
||||
mass 3 5.18 0. 0.; # node#, Mx My Mz, Mass=Weight/g.
|
||||
mass 4 5.18 0. 0.
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
geomTransf Linear 1; # associate a tag to transformation
|
||||
|
||||
# connectivity: (make A very large, 10e6 times its actual value)
|
||||
element elasticBeamColumn 1 1 3 3600000000 4227 1080000 1; # element elasticBeamColumn $eleTag $iNode $jNode $A $E $Iz $transfTag
|
||||
element elasticBeamColumn 2 2 4 3600000000 4227 1080000 1
|
||||
element elasticBeamColumn 3 3 4 5760000000 4227 4423680 1
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 3 4 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 2 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 2 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 2 -jNode 3 4 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 2 globalForce; # element forces -- column
|
||||
recorder Element -file Data/FBeam.out -time -ele 3 globalForce; # element forces -- beam
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
eleLoad -ele 3 -type -beamUniform -7.94 ; # distributed superstructure-weight on beam
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr 1.0e-8 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
integrator LoadControl 0.1; # determine the next time step for an analysis, # apply gravity in 10 steps
|
||||
analysis Static # define type of analysis static or transient
|
||||
analyze 10; # perform gravity analysis
|
||||
loadConst -time 0.0; # hold gravity constant and restart time
|
||||
|
||||
# define LATERAL load -------------------------------------------------------------
|
||||
# Lateral load pattern
|
||||
pattern Plain 2 Linear {
|
||||
load 3 2000. 0.0 0.0; # node#, FX FY MZ -- representative lateral load at top nodes
|
||||
load 4 2000. 0.0 0.0; # place 1/2 of the weight for each node to get shear coefficient
|
||||
}
|
||||
|
||||
# pushover: diplacement controlled static analysis
|
||||
integrator DisplacementControl 3 1 0.1; # switch to displacement control, for node 11, dof 1, 0.1 increment
|
||||
analyze 100; # apply 100 steps of pushover analysis to a displacement of 10
|
||||
|
||||
puts "Done!"
|
||||
|
||||
|
||||
|
||||
|
||||
231
examples/data/Ex2a.Canti2D.ElasticElement.EQ.tcl.txt
Normal file
231
examples/data/Ex2a.Canti2D.ElasticElement.EQ.tcl.txt
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 2. 2D cantilever column, dynamic eq ground motion
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
# units: kip, inch, sec
|
||||
wipe; # clear memory of all past model definitions
|
||||
file mkdir Data; # create data directory
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol 432; # column length
|
||||
set Weight 2000; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol 60; # Column Depth
|
||||
set BCol 60; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol $Weight; # nodal dead-load weight per column
|
||||
set g 386.4; # g.
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol*1000]; # cross-sectional area, make stiff
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# Material parameters
|
||||
set fc -4.; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*sqrt(-$fc*1000)]; # Concrete Elastic Modulus (the term in sqr root needs to be in psi
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
geomTransf Linear $ColTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
element elasticBeamColumn 1 1 2 $ACol $Ec $IzCol $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 globalForce; # element forces -- column
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------- apply gravity load
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
|
||||
# DYNAMIC EQ ANALYSIS --------------------------------------------------------
|
||||
# Uniform Earthquake ground motion (uniform acceleration input at all support nodes)
|
||||
set GMdirection 1; # ground-motion direction
|
||||
set GMfile "BM68elc.acc" ; # ground-motion filenames
|
||||
set GMfact 1.; # ground-motion scaling factor
|
||||
|
||||
# set up ground-motion-analysis parameters
|
||||
set DtAnalysis [expr 0.01]; # time-step Dt for lateral analysis
|
||||
set TmaxAnalysis [expr 10.]; # maximum duration of ground-motion analysis -- should be 50*$sec
|
||||
|
||||
# DYNAMIC ANALYSIS PARAMETERS
|
||||
# CONSTRAINTS handler -- Determines how the constraint equations are enforced in the analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/617.htm)
|
||||
# Plain Constraints -- Removes constrained degrees of freedom from the system of equations
|
||||
# Lagrange Multipliers -- Uses the method of Lagrange multipliers to enforce constraints
|
||||
# Penalty Method -- Uses penalty numbers to enforce constraints
|
||||
# Transformation Method -- Performs a condensation of constrained degrees of freedom
|
||||
constraints Transformation ;
|
||||
|
||||
# DOF NUMBERER (number the degrees of freedom in the domain): (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/366.htm)
|
||||
# determines the mapping between equation numbers and degrees-of-freedom
|
||||
# Plain -- Uses the numbering provided by the user
|
||||
# RCM -- Renumbers the DOF to minimize the matrix band-width using the Reverse Cuthill-McKee algorithm
|
||||
numberer Plain
|
||||
|
||||
# SYSTEM (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/371.htm)
|
||||
# Linear Equation Solvers (how to store and solve the system of equations in the analysis)
|
||||
# -- provide the solution of the linear system of equations Ku = P. Each solver is tailored to a specific matrix topology.
|
||||
# ProfileSPD -- Direct profile solver for symmetric positive definite matrices
|
||||
# BandGeneral -- Direct solver for banded unsymmetric matrices
|
||||
# BandSPD -- Direct solver for banded symmetric positive definite matrices
|
||||
# SparseGeneral -- Direct solver for unsymmetric sparse matrices (-piv option)
|
||||
# SparseSPD -- Direct solver for symmetric sparse matrices
|
||||
# UmfPack -- Direct UmfPack solver for unsymmetric matrices
|
||||
system SparseGeneral -piv
|
||||
|
||||
# TEST: # convergence test to
|
||||
# Convergence TEST (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/360.htm)
|
||||
# -- Accept the current state of the domain as being on the converged solution path
|
||||
# -- determine if convergence has been achieved at the end of an iteration step
|
||||
# NormUnbalance -- Specifies a tolerance on the norm of the unbalanced load at the current iteration
|
||||
# NormDispIncr -- Specifies a tolerance on the norm of the displacement increments at the current iteration
|
||||
# EnergyIncr-- Specifies a tolerance on the inner product of the unbalanced load and displacement increments at the current iteration
|
||||
# RelativeNormUnbalance --
|
||||
# RelativeNormDispIncr --
|
||||
# RelativeEnergyIncr --
|
||||
set Tol 1.e-8; # Convergence Test: tolerance
|
||||
set maxNumIter 10; # Convergence Test: maximum number of iterations that will be performed before "failure to converge" is returned
|
||||
set printFlag 0; # Convergence Test: flag used to print information on convergence (optional) # 1: print information on each step;
|
||||
set TestType EnergyIncr; # Convergence-test type
|
||||
test $TestType $Tol $maxNumIter $printFlag;
|
||||
|
||||
# Solution ALGORITHM: -- Iterate from the last time step to the current (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/682.htm)
|
||||
# Linear -- Uses the solution at the first iteration and continues
|
||||
# Newton -- Uses the tangent at the current iteration to iterate to convergence
|
||||
# ModifiedNewton -- Uses the tangent at the first iteration to iterate to convergence
|
||||
# NewtonLineSearch --
|
||||
# KrylovNewton --
|
||||
# BFGS --
|
||||
# Broyden --
|
||||
set algorithmType ModifiedNewton
|
||||
algorithm $algorithmType;
|
||||
|
||||
# Static INTEGRATOR: -- determine the next time step for an analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/689.htm)
|
||||
# LoadControl -- Specifies the incremental load factor to be applied to the loads in the domain
|
||||
# DisplacementControl -- Specifies the incremental displacement at a specified DOF in the domain
|
||||
# Minimum Unbalanced Displacement Norm -- Specifies the incremental load factor such that the residual displacement norm in minimized
|
||||
# Arc Length -- Specifies the incremental arc-length of the load-displacement path
|
||||
# Transient INTEGRATOR: -- determine the next time step for an analysis including inertial effects
|
||||
# Newmark -- The two parameter time-stepping method developed by Newmark
|
||||
# HHT -- The three parameter Hilbert-Hughes-Taylor time-stepping method
|
||||
# Central Difference -- Approximates velocity and acceleration by centered finite differences of displacement
|
||||
set NewmarkGamma 0.5; # Newmark-integrator gamma parameter (also HHT)
|
||||
set NewmarkBeta 0.25; # Newmark-integrator beta parameter
|
||||
integrator Newmark $NewmarkGamma $NewmarkBeta
|
||||
|
||||
# ANALYSIS -- defines what type of analysis is to be performed (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/324.htm)
|
||||
# Static Analysis -- solves the KU=R problem, without the mass or damping matrices.
|
||||
# Transient Analysis -- solves the time-dependent analysis. The time step in this type of analysis is constant. The time step in the output is also constant.
|
||||
# variableTransient Analysis -- performs the same analysis type as the Transient Analysis object. The time step, however, is variable. This method is used when
|
||||
# there are convergence problems with the Transient Analysis object at a peak or when the time step is too small. The time step in the output is also variable.
|
||||
analysis Transient
|
||||
|
||||
# define DAMPING--------------------------------------------------------------------------------------
|
||||
# apply Rayleigh DAMPING from $xDamp
|
||||
# D=$alphaM*M + $betaKcurr*Kcurrent + $betaKcomm*KlastCommit + $beatKinit*$Kinitial
|
||||
set xDamp 0.02; # 2% damping ratio
|
||||
set lambda [eigen 1]; # eigenvalue mode 1
|
||||
set omega [expr pow($lambda,0.5)];
|
||||
set alphaM 0.; # M-prop. damping; D = alphaM*M
|
||||
set betaKcurr 0.; # K-proportional damping; +beatKcurr*KCurrent
|
||||
set betaKcomm [expr 2.*$xDamp/($omega)]; # K-prop. damping parameter; +betaKcomm*KlastCommitt
|
||||
set betaKinit 0.; # initial-stiffness proportional damping +beatKinit*Kini
|
||||
# define damping
|
||||
rayleigh $alphaM $betaKcurr $betaKinit $betaKcomm; # RAYLEIGH damping
|
||||
|
||||
# --------------------------------- perform Dynamic Ground-Motion Analysis
|
||||
# Uniform EXCITATION: acceleration input
|
||||
set IDloadTag 400; # load tag
|
||||
set dt 0.01; # time step for input ground motion
|
||||
set GMfatt 1.0; # data in input file is in g Unifts -- ACCELERATION TH
|
||||
set AccelSeries "Series -dt $dt -filePath $GMfile -factor $GMfatt"; # time series information
|
||||
pattern UniformExcitation $IDloadTag $GMdirection -accel $AccelSeries ; # create Unifform excitation
|
||||
|
||||
set Nsteps [expr int($TmaxAnalysis/$DtAnalysis)];
|
||||
set ok [analyze $Nsteps $DtAnalysis]; # actually perform analysis; returns ok=0 if analysis was successful
|
||||
|
||||
if {$ok != 0} { ; # if analysis was not successful.
|
||||
# change some analysis parameters to achieve convergence
|
||||
# performance is slower inside this loop
|
||||
# Time-controlled analysis
|
||||
set ok 0;
|
||||
set controlTime [getTime];
|
||||
while {$controlTime < $TmaxAnalysis && $ok == 0} {
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
set controlTime [getTime]
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 1000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
test $TestType $Tol $maxNumIter 0
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
}
|
||||
}; # end if ok !0
|
||||
|
||||
|
||||
puts "Ground Motion Done. End Time: [getTime]"
|
||||
207
examples/data/Ex2a.Canti2D.ElasticElement.Push.tcl.txt
Normal file
207
examples/data/Ex2a.Canti2D.ElasticElement.Push.tcl.txt
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 2. 2D cantilever column, static pushover
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
# units: kip, inch, sec
|
||||
wipe; # clear memory of all past model definitions
|
||||
file mkdir Data; # create data directory
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol 432; # column length
|
||||
set Weight 2000; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol 60; # Column Depth
|
||||
set BCol 60; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol $Weight; # nodal dead-load weight per column
|
||||
set g 386.4; # g.
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol*1000]; # cross-sectional area, make stiff
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# Material parameters
|
||||
set fc -4.; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*sqrt(-$fc*1000)]; # Concrete Elastic Modulus (the term in sqr root needs to be in psi
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
geomTransf Linear $ColTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
element elasticBeamColumn 1 1 2 $ACol $Ec $IzCol $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 1 globalForce; # element forces -- column
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------- apply gravity load
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
|
||||
# STATIC PUSHOVER ANALYSIS --------------------------------------------------------------------------------------------------
|
||||
#
|
||||
# we need to set up parameters that are particular to the model.
|
||||
set IDctrlNode 2; # node where displacement is read for displacement control
|
||||
set IDctrlDOF 1; # degree of freedom of displacement read for displacement contro
|
||||
set Dmax [expr 0.01*$LCol]; # maximum displacement of pushover. push to 10% drift.
|
||||
set Dincr [expr 0.001*$LCol]; # displacement increment for pushover. you want this to be very small, but not too small to slow down the analysis
|
||||
|
||||
# create load pattern for lateral pushover load
|
||||
set Hload $Weight; # define the lateral load as a proportion of the weight so that the pseudo time equals the lateral-load coefficient when using linear load pattern
|
||||
pattern Plain 200 Linear {; # define load pattern -- generalized
|
||||
load 2 $Hload 0.0 0.0 0.0 0.0 0.0; # define lateral load in static lateral analysis
|
||||
}
|
||||
|
||||
# ----------- set up analysis parameters
|
||||
# CONSTRAINTS handler -- Determines how the constraint equations are enforced in the analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/617.htm)
|
||||
# Plain Constraints -- Removes constrained degrees of freedom from the system of equations (only for homogeneous equations)
|
||||
# Lagrange Multipliers -- Uses the method of Lagrange multipliers to enforce constraints
|
||||
# Penalty Method -- Uses penalty numbers to enforce constraints --good for static analysis with non-homogeneous eqns (rigidDiaphragm)
|
||||
# Transformation Method -- Performs a condensation of constrained degrees of freedom
|
||||
constraints Plain;
|
||||
|
||||
# DOF NUMBERER (number the degrees of freedom in the domain): (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/366.htm)
|
||||
# determines the mapping between equation numbers and degrees-of-freedom
|
||||
# Plain -- Uses the numbering provided by the user
|
||||
# RCM -- Renumbers the DOF to minimize the matrix band-width using the Reverse Cuthill-McKee algorithm
|
||||
numberer Plain
|
||||
|
||||
# SYSTEM (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/371.htm)
|
||||
# Linear Equation Solvers (how to store and solve the system of equations in the analysis)
|
||||
# -- provide the solution of the linear system of equations Ku = P. Each solver is tailored to a specific matrix topology.
|
||||
# ProfileSPD -- Direct profile solver for symmetric positive definite matrices
|
||||
# BandGeneral -- Direct solver for banded unsymmetric matrices
|
||||
# BandSPD -- Direct solver for banded symmetric positive definite matrices
|
||||
# SparseGeneral -- Direct solver for unsymmetric sparse matrices
|
||||
# SparseSPD -- Direct solver for symmetric sparse matrices
|
||||
# UmfPack -- Direct UmfPack solver for unsymmetric matrices
|
||||
system BandGeneral
|
||||
|
||||
# TEST: # convergence test to
|
||||
# Convergence TEST (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/360.htm)
|
||||
# -- Accept the current state of the domain as being on the converged solution path
|
||||
# -- determine if convergence has been achieved at the end of an iteration step
|
||||
# NormUnbalance -- Specifies a tolerance on the norm of the unbalanced load at the current iteration
|
||||
# NormDispIncr -- Specifies a tolerance on the norm of the displacement increments at the current iteration
|
||||
# EnergyIncr-- Specifies a tolerance on the inner product of the unbalanced load and displacement increments at the current iteration
|
||||
set Tol 1.e-8; # Convergence Test: tolerance
|
||||
set maxNumIter 6; # Convergence Test: maximum number of iterations that will be performed before "failure to converge" is returned
|
||||
set printFlag 0; # Convergence Test: flag used to print information on convergence (optional) # 1: print information on each step;
|
||||
set TestType EnergyIncr ; # Convergence-test type
|
||||
test $TestType $Tol $maxNumIter $printFlag;
|
||||
|
||||
# Solution ALGORITHM: -- Iterate from the last time step to the current (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/682.htm)
|
||||
# Linear -- Uses the solution at the first iteration and continues
|
||||
# Newton -- Uses the tangent at the current iteration to iterate to convergence
|
||||
# ModifiedNewton -- Uses the tangent at the first iteration to iterate to convergence
|
||||
set algorithmType Newton
|
||||
algorithm $algorithmType;
|
||||
|
||||
# Static INTEGRATOR: -- determine the next time step for an analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/689.htm)
|
||||
# LoadControl -- Specifies the incremental load factor to be applied to the loads in the domain
|
||||
# DisplacementControl -- Specifies the incremental displacement at a specified DOF in the domain
|
||||
# Minimum Unbalanced Displacement Norm -- Specifies the incremental load factor such that the residual displacement norm in minimized
|
||||
# Arc Length -- Specifies the incremental arc-length of the load-displacement path
|
||||
# Transient INTEGRATOR: -- determine the next time step for an analysis including inertial effects
|
||||
# Newmark -- The two parameter time-stepping method developed by Newmark
|
||||
# HHT -- The three parameter Hilbert-Hughes-Taylor time-stepping method
|
||||
# Central Difference -- Approximates velocity and acceleration by centered finite differences of displacement
|
||||
integrator DisplacementControl $IDctrlNode $IDctrlDOF $Dincr
|
||||
|
||||
# ANALYSIS -- defines what type of analysis is to be performed (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/324.htm)
|
||||
# Static Analysis -- solves the KU=R problem, without the mass or damping matrices.
|
||||
# Transient Analysis -- solves the time-dependent analysis. The time step in this type of analysis is constant. The time step in the output is also constant.
|
||||
# variableTransient Analysis -- performs the same analysis type as the Transient Analysis object. The time step, however, is variable. This method is used when
|
||||
# there are convergence problems with the Transient Analysis object at a peak or when the time step is too small. The time step in the output is also variable.
|
||||
analysis Static
|
||||
|
||||
# --------------------------------- perform Static Pushover Analysis
|
||||
set Nsteps [expr int($Dmax/$Dincr)]; # number of pushover analysis steps
|
||||
set ok [analyze $Nsteps]; # this will return zero if no convergence problems were encountered
|
||||
|
||||
# ---------------------------------- in case of convergence problems
|
||||
if {$ok != 0} {
|
||||
# change some analysis parameters to achieve convergence
|
||||
# performance is slower inside this loop
|
||||
set ok 0;
|
||||
set controlDisp 0.0; # start from zero
|
||||
set D0 0.0; # start from zero
|
||||
set Dstep [expr ($controlDisp-$D0)/($Dmax-$D0)]
|
||||
while {$Dstep < 1.0 && $ok == 0} {
|
||||
set controlDisp [nodeDisp $IDctrlNode $IDctrlDOF ]
|
||||
set Dstep [expr ($controlDisp-$D0)/($Dmax-$D0)]
|
||||
set ok [analyze 1 ]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 2000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 ]
|
||||
test $TestType $Tol $maxNumIter 0
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
}
|
||||
}; # end if ok !0
|
||||
|
||||
puts "DonePushover"
|
||||
256
examples/data/Ex2b.Canti2D.InelasticSection.EQ.tcl.txt
Normal file
256
examples/data/Ex2b.Canti2D.InelasticSection.EQ.tcl.txt
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 2. 2D cantilever column, dynamic eq ground motion
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
# units: kip, inch, sec
|
||||
wipe; # clear memory of all past model definitions
|
||||
file mkdir Data; # create data directory
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol 432; # column length
|
||||
set Weight 2000.; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol 60; # Column Depth
|
||||
set BCol 60; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol $Weight; # nodal dead-load weight per column
|
||||
set g 386.4; # g.
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol*1000]; # cross-sectional area, make stiff
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS & SECTIONS -------------------------------------------------------------
|
||||
set ColMatTagFlex 2; # assign a tag number to the column flexural behavior
|
||||
set ColMatTagAxial 3; # assign a tag number to the column axial behavior
|
||||
set ColSecTag 1; # assign a tag number to the column section tag
|
||||
set BeamSecTag 2; # assign a tag number to the beam section tag
|
||||
|
||||
# MATERIAL parameters
|
||||
set fc -4.; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*sqrt(-$fc*1000)]; # Concrete Elastic Modulus (the term in sqr root needs to be in psi
|
||||
|
||||
# COLUMN section
|
||||
# calculated stiffness parameters
|
||||
set EICol [expr $Ec*$IzCol]; # EI, for moment-curvature relationship
|
||||
set EACol [expr $Ec*$ACol]; # EA, for axial-force-strain relationship
|
||||
set MyCol 130000; # yield moment
|
||||
set PhiYCol 0.65e-4; # yield curvature
|
||||
set EIColCrack [expr $MyCol/$PhiYCol]; # cracked section inertia
|
||||
set b 0.01 ; # strain-hardening ratio (ratio between post-yield tangent and initial elastic tangent)
|
||||
uniaxialMaterial Steel01 $ColMatTagFlex $MyCol $EIColCrack $b; # bilinear behavior for flexure
|
||||
uniaxialMaterial Elastic $ColMatTagAxial $EACol; # this is not used as a material, this is an axial-force-strain response
|
||||
section Aggregator $ColSecTag $ColMatTagAxial P $ColMatTagFlex Mz; # combine axial and flexural behavior into one section (no P-M interaction here)
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
geomTransf Linear $ColTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
set numIntgrPts 5; # number of integration points for force-based element
|
||||
element nonlinearBeamColumn 1 1 2 $numIntgrPts $ColSecTag $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 2 globalForce; # element forces -- column
|
||||
recorder Element -file Data/ForceColSec1.out -time -ele 1 section 1 force; # Column section forces, axial and moment, node i
|
||||
recorder Element -file Data/DefoColSec1.out -time -ele 1 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file Data/ForceColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file Data/DefoColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# Gravity-analysis parameters -- load-controlled static analysis
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
|
||||
# DYNAMIC EQ ANALYSIS --------------------------------------------------------
|
||||
# Uniform Earthquake ground motion (uniform acceleration input at all support nodes)
|
||||
set GMdirection 1; # ground-motion direction
|
||||
set GMfile "BM68elc.acc" ; # ground-motion filenames
|
||||
set GMfact 1.; # ground-motion scaling factor
|
||||
|
||||
# set up ground-motion-analysis parameters
|
||||
set DtAnalysis [expr 0.01]; # time-step Dt for lateral analysis
|
||||
set TmaxAnalysis [expr 10.]; # maximum duration of ground-motion analysis -- should be 50*$sec
|
||||
|
||||
# DYNAMIC ANALYSIS PARAMETERS
|
||||
# CONSTRAINTS handler -- Determines how the constraint equations are enforced in the analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/617.htm)
|
||||
# Plain Constraints -- Removes constrained degrees of freedom from the system of equations
|
||||
# Lagrange Multipliers -- Uses the method of Lagrange multipliers to enforce constraints
|
||||
# Penalty Method -- Uses penalty numbers to enforce constraints
|
||||
# Transformation Method -- Performs a condensation of constrained degrees of freedom
|
||||
constraints Transformation ;
|
||||
|
||||
# DOF NUMBERER (number the degrees of freedom in the domain): (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/366.htm)
|
||||
# determines the mapping between equation numbers and degrees-of-freedom
|
||||
# Plain -- Uses the numbering provided by the user
|
||||
# RCM -- Renumbers the DOF to minimize the matrix band-width using the Reverse Cuthill-McKee algorithm
|
||||
numberer Plain
|
||||
|
||||
# SYSTEM (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/371.htm)
|
||||
# Linear Equation Solvers (how to store and solve the system of equations in the analysis)
|
||||
# -- provide the solution of the linear system of equations Ku = P. Each solver is tailored to a specific matrix topology.
|
||||
# ProfileSPD -- Direct profile solver for symmetric positive definite matrices
|
||||
# BandGeneral -- Direct solver for banded unsymmetric matrices
|
||||
# BandSPD -- Direct solver for banded symmetric positive definite matrices
|
||||
# SparseGeneral -- Direct solver for unsymmetric sparse matrices (-piv option)
|
||||
# SparseSPD -- Direct solver for symmetric sparse matrices
|
||||
# UmfPack -- Direct UmfPack solver for unsymmetric matrices
|
||||
system SparseGeneral -piv
|
||||
|
||||
# TEST: # convergence test to
|
||||
# Convergence TEST (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/360.htm)
|
||||
# -- Accept the current state of the domain as being on the converged solution path
|
||||
# -- determine if convergence has been achieved at the end of an iteration step
|
||||
# NormUnbalance -- Specifies a tolerance on the norm of the unbalanced load at the current iteration
|
||||
# NormDispIncr -- Specifies a tolerance on the norm of the displacement increments at the current iteration
|
||||
# EnergyIncr-- Specifies a tolerance on the inner product of the unbalanced load and displacement increments at the current iteration
|
||||
# RelativeNormUnbalance --
|
||||
# RelativeNormDispIncr --
|
||||
# RelativeEnergyIncr --
|
||||
set Tol 1.e-8; # Convergence Test: tolerance
|
||||
set maxNumIter 10; # Convergence Test: maximum number of iterations that will be performed before "failure to converge" is returned
|
||||
set printFlag 0; # Convergence Test: flag used to print information on convergence (optional) # 1: print information on each step;
|
||||
set TestType EnergyIncr; # Convergence-test type
|
||||
test $TestType $Tol $maxNumIter $printFlag;
|
||||
|
||||
# Solution ALGORITHM: -- Iterate from the last time step to the current (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/682.htm)
|
||||
# Linear -- Uses the solution at the first iteration and continues
|
||||
# Newton -- Uses the tangent at the current iteration to iterate to convergence
|
||||
# ModifiedNewton -- Uses the tangent at the first iteration to iterate to convergence
|
||||
# NewtonLineSearch --
|
||||
# KrylovNewton --
|
||||
# BFGS --
|
||||
# Broyden --
|
||||
set algorithmType ModifiedNewton
|
||||
algorithm $algorithmType;
|
||||
|
||||
# Static INTEGRATOR: -- determine the next time step for an analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/689.htm)
|
||||
# LoadControl -- Specifies the incremental load factor to be applied to the loads in the domain
|
||||
# DisplacementControl -- Specifies the incremental displacement at a specified DOF in the domain
|
||||
# Minimum Unbalanced Displacement Norm -- Specifies the incremental load factor such that the residual displacement norm in minimized
|
||||
# Arc Length -- Specifies the incremental arc-length of the load-displacement path
|
||||
# Transient INTEGRATOR: -- determine the next time step for an analysis including inertial effects
|
||||
# Newmark -- The two parameter time-stepping method developed by Newmark
|
||||
# HHT -- The three parameter Hilbert-Hughes-Taylor time-stepping method
|
||||
# Central Difference -- Approximates velocity and acceleration by centered finite differences of displacement
|
||||
set NewmarkGamma 0.5; # Newmark-integrator gamma parameter (also HHT)
|
||||
set NewmarkBeta 0.25; # Newmark-integrator beta parameter
|
||||
integrator Newmark $NewmarkGamma $NewmarkBeta
|
||||
|
||||
# ANALYSIS -- defines what type of analysis is to be performed (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/324.htm)
|
||||
# Static Analysis -- solves the KU=R problem, without the mass or damping matrices.
|
||||
# Transient Analysis -- solves the time-dependent analysis. The time step in this type of analysis is constant. The time step in the output is also constant.
|
||||
# variableTransient Analysis -- performs the same analysis type as the Transient Analysis object. The time step, however, is variable. This method is used when
|
||||
# there are convergence problems with the Transient Analysis object at a peak or when the time step is too small. The time step in the output is also variable.
|
||||
analysis Transient
|
||||
|
||||
# define DAMPING--------------------------------------------------------------------------------------
|
||||
# apply Rayleigh DAMPING from $xDamp
|
||||
# D=$alphaM*M + $betaKcurr*Kcurrent + $betaKcomm*KlastCommit + $beatKinit*$Kinitial
|
||||
set xDamp 0.02; # 2% damping ratio
|
||||
set lambda [eigen 1]; # eigenvalue mode 1
|
||||
set omega [expr pow($lambda,0.5)];
|
||||
set alphaM 0.; # M-prop. damping; D = alphaM*M
|
||||
set betaKcurr 0.; # K-proportional damping; +beatKcurr*KCurrent
|
||||
set betaKcomm [expr 2.*$xDamp/($omega)]; # K-prop. damping parameter; +betaKcomm*KlastCommitt
|
||||
set betaKinit 0.; # initial-stiffness proportional damping +beatKinit*Kini
|
||||
# define damping
|
||||
rayleigh $alphaM $betaKcurr $betaKinit $betaKcomm; # RAYLEIGH damping
|
||||
|
||||
# --------------------------------- perform Dynamic Ground-Motion Analysis
|
||||
# Uniform EXCITATION: acceleration input
|
||||
set IDloadTag 400; # load tag
|
||||
set dt 0.01; # time step for input ground motion
|
||||
set GMfatt 1.0; # data in input file is in g Unifts -- ACCELERATION TH
|
||||
set AccelSeries "Series -dt $dt -filePath $GMfile -factor $GMfatt"; # time series information
|
||||
pattern UniformExcitation $IDloadTag $GMdirection -accel $AccelSeries ; # create Unifform excitation
|
||||
|
||||
set Nsteps [expr int($TmaxAnalysis/$DtAnalysis)];
|
||||
set ok [analyze $Nsteps $DtAnalysis]; # actually perform analysis; returns ok=0 if analysis was successful
|
||||
|
||||
if {$ok != 0} { ; # if analysis was not successful.
|
||||
# change some analysis parameters to achieve convergence
|
||||
# performance is slower inside this loop
|
||||
# Time-controlled analysis
|
||||
set ok 0;
|
||||
set controlTime [getTime];
|
||||
while {$controlTime < $TmaxAnalysis && $ok == 0} {
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
set controlTime [getTime]
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 1000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
test $TestType $Tol $maxNumIter 0
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
}
|
||||
}; # end if ok !0
|
||||
|
||||
|
||||
|
||||
puts "Ground Motion Done. End Time: [getTime]"
|
||||
233
examples/data/Ex2b.Canti2D.InelasticSection.Push.tcl.txt
Normal file
233
examples/data/Ex2b.Canti2D.InelasticSection.Push.tcl.txt
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 2. 2D cantilever column, static pushover
|
||||
# element
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
# units: kip, inch, sec
|
||||
wipe; # clear memory of all past model definitions
|
||||
file mkdir Data; # create data directory
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol 432; # column length
|
||||
set Weight 2000.; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol 60; # Column Depth
|
||||
set BCol 60; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol $Weight; # nodal dead-load weight per column
|
||||
set g 386.4; # g.
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol*1000]; # cross-sectional area, make stiff
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS & SECTIONS -------------------------------------------------------------
|
||||
set ColMatTagFlex 2; # assign a tag number to the column flexural behavior
|
||||
set ColMatTagAxial 3; # assign a tag number to the column axial behavior
|
||||
set ColSecTag 1; # assign a tag number to the column section tag
|
||||
set BeamSecTag 2; # assign a tag number to the beam section tag
|
||||
|
||||
# MATERIAL parameters
|
||||
set fc -4.; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*sqrt(-$fc*1000)]; # Concrete Elastic Modulus (the term in sqr root needs to be in psi
|
||||
|
||||
# COLUMN section
|
||||
# calculated stiffness parameters
|
||||
set EICol [expr $Ec*$IzCol]; # EI, for moment-curvature relationship
|
||||
set EACol [expr $Ec*$ACol]; # EA, for axial-force-strain relationship
|
||||
set MyCol 130000; # yield moment
|
||||
set PhiYCol 0.65e-4; # yield curvature
|
||||
set EIColCrack [expr $MyCol/$PhiYCol]; # cracked section inertia
|
||||
set b 0.01 ; # strain-hardening ratio (ratio between post-yield tangent and initial elastic tangent)
|
||||
uniaxialMaterial Steel01 $ColMatTagFlex $MyCol $EIColCrack $b; # bilinear behavior for flexure
|
||||
uniaxialMaterial Elastic $ColMatTagAxial $EACol; # this is not used as a material, this is an axial-force-strain response
|
||||
section Aggregator $ColSecTag $ColMatTagAxial P $ColMatTagFlex Mz; # combine axial and flexural behavior into one section (no P-M interaction here)
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
geomTransf Linear $ColTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
set numIntgrPts 5; # number of integration points for force-based element
|
||||
element nonlinearBeamColumn 1 1 2 $numIntgrPts $ColSecTag $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file Data/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file Data/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file Data/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file Data/FCol.out -time -ele 2 globalForce; # element forces -- column
|
||||
recorder Element -file Data/ForceColSec1.out -time -ele 1 section 1 force; # Column section forces, axial and moment, node i
|
||||
recorder Element -file Data/DefoColSec1.out -time -ele 1 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file Data/ForceColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file Data/DefoColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# Gravity-analysis parameters -- load-controlled static analysis
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
|
||||
# STATIC PUSHOVER ANALYSIS --------------------------------------------------------------------------------------------------
|
||||
#
|
||||
# we need to set up parameters that are particular to the model.
|
||||
set IDctrlNode 2; # node where displacement is read for displacement control
|
||||
set IDctrlDOF 1; # degree of freedom of displacement read for displacement contro
|
||||
set Dmax [expr 0.05*$LCol]; # maximum displacement of pushover. push to 10% drift.
|
||||
set Dincr [expr 0.001*$LCol]; # displacement increment for pushover. you want this to be very small, but not too small to slow down the analysis
|
||||
|
||||
# create load pattern for lateral pushover load
|
||||
set Hload $Weight; # define the lateral load as a proportion of the weight so that the pseudo time equals the lateral-load coefficient when using linear load pattern
|
||||
pattern Plain 200 Linear {; # define load pattern -- generalized
|
||||
load 2 $Hload 0.0 0.0 0.0 0.0 0.0; # define lateral load in static lateral analysis
|
||||
}
|
||||
|
||||
# ----------- set up analysis parameters
|
||||
# CONSTRAINTS handler -- Determines how the constraint equations are enforced in the analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/617.htm)
|
||||
# Plain Constraints -- Removes constrained degrees of freedom from the system of equations (only for homogeneous equations)
|
||||
# Lagrange Multipliers -- Uses the method of Lagrange multipliers to enforce constraints
|
||||
# Penalty Method -- Uses penalty numbers to enforce constraints --good for static analysis with non-homogeneous eqns (rigidDiaphragm)
|
||||
# Transformation Method -- Performs a condensation of constrained degrees of freedom
|
||||
constraints Plain;
|
||||
|
||||
# DOF NUMBERER (number the degrees of freedom in the domain): (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/366.htm)
|
||||
# determines the mapping between equation numbers and degrees-of-freedom
|
||||
# Plain -- Uses the numbering provided by the user
|
||||
# RCM -- Renumbers the DOF to minimize the matrix band-width using the Reverse Cuthill-McKee algorithm
|
||||
numberer Plain
|
||||
|
||||
# SYSTEM (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/371.htm)
|
||||
# Linear Equation Solvers (how to store and solve the system of equations in the analysis)
|
||||
# -- provide the solution of the linear system of equations Ku = P. Each solver is tailored to a specific matrix topology.
|
||||
# ProfileSPD -- Direct profile solver for symmetric positive definite matrices
|
||||
# BandGeneral -- Direct solver for banded unsymmetric matrices
|
||||
# BandSPD -- Direct solver for banded symmetric positive definite matrices
|
||||
# SparseGeneral -- Direct solver for unsymmetric sparse matrices
|
||||
# SparseSPD -- Direct solver for symmetric sparse matrices
|
||||
# UmfPack -- Direct UmfPack solver for unsymmetric matrices
|
||||
system BandGeneral
|
||||
|
||||
# TEST: # convergence test to
|
||||
# Convergence TEST (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/360.htm)
|
||||
# -- Accept the current state of the domain as being on the converged solution path
|
||||
# -- determine if convergence has been achieved at the end of an iteration step
|
||||
# NormUnbalance -- Specifies a tolerance on the norm of the unbalanced load at the current iteration
|
||||
# NormDispIncr -- Specifies a tolerance on the norm of the displacement increments at the current iteration
|
||||
# EnergyIncr-- Specifies a tolerance on the inner product of the unbalanced load and displacement increments at the current iteration
|
||||
set Tol 1.e-8; # Convergence Test: tolerance
|
||||
set maxNumIter 6; # Convergence Test: maximum number of iterations that will be performed before "failure to converge" is returned
|
||||
set printFlag 0; # Convergence Test: flag used to print information on convergence (optional) # 1: print information on each step;
|
||||
set TestType EnergyIncr ; # Convergence-test type
|
||||
test $TestType $Tol $maxNumIter $printFlag;
|
||||
|
||||
# Solution ALGORITHM: -- Iterate from the last time step to the current (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/682.htm)
|
||||
# Linear -- Uses the solution at the first iteration and continues
|
||||
# Newton -- Uses the tangent at the current iteration to iterate to convergence
|
||||
# ModifiedNewton -- Uses the tangent at the first iteration to iterate to convergence
|
||||
set algorithmType Newton
|
||||
algorithm $algorithmType;
|
||||
|
||||
# Static INTEGRATOR: -- determine the next time step for an analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/689.htm)
|
||||
# LoadControl -- Specifies the incremental load factor to be applied to the loads in the domain
|
||||
# DisplacementControl -- Specifies the incremental displacement at a specified DOF in the domain
|
||||
# Minimum Unbalanced Displacement Norm -- Specifies the incremental load factor such that the residual displacement norm in minimized
|
||||
# Arc Length -- Specifies the incremental arc-length of the load-displacement path
|
||||
# Transient INTEGRATOR: -- determine the next time step for an analysis including inertial effects
|
||||
# Newmark -- The two parameter time-stepping method developed by Newmark
|
||||
# HHT -- The three parameter Hilbert-Hughes-Taylor time-stepping method
|
||||
# Central Difference -- Approximates velocity and acceleration by centered finite differences of displacement
|
||||
integrator DisplacementControl $IDctrlNode $IDctrlDOF $Dincr
|
||||
|
||||
# ANALYSIS -- defines what type of analysis is to be performed (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/324.htm)
|
||||
# Static Analysis -- solves the KU=R problem, without the mass or damping matrices.
|
||||
# Transient Analysis -- solves the time-dependent analysis. The time step in this type of analysis is constant. The time step in the output is also constant.
|
||||
# variableTransient Analysis -- performs the same analysis type as the Transient Analysis object. The time step, however, is variable. This method is used when
|
||||
# there are convergence problems with the Transient Analysis object at a peak or when the time step is too small. The time step in the output is also variable.
|
||||
analysis Static
|
||||
|
||||
# --------------------------------- perform Static Pushover Analysis
|
||||
set Nsteps [expr int($Dmax/$Dincr)]; # number of pushover analysis steps
|
||||
set ok [analyze $Nsteps]; # this will return zero if no convergence problems were encountered
|
||||
|
||||
# ---------------------------------- in case of convergence problems
|
||||
if {$ok != 0} {
|
||||
# change some analysis parameters to achieve convergence
|
||||
# performance is slower inside this loop
|
||||
set ok 0;
|
||||
set controlDisp 0.0; # start from zero
|
||||
set D0 0.0; # start from zero
|
||||
set Dstep [expr ($controlDisp-$D0)/($Dmax-$D0)]
|
||||
while {$Dstep < 1.0 && $ok == 0} {
|
||||
set controlDisp [nodeDisp $IDctrlNode $IDctrlDOF ]
|
||||
set Dstep [expr ($controlDisp-$D0)/($Dmax-$D0)]
|
||||
set ok [analyze 1 ]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 2000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 ]
|
||||
test $TestType $Tol $maxNumIter 0
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
}
|
||||
}; # end if ok !0
|
||||
|
||||
puts "DonePushover"
|
||||
|
||||
147
examples/data/Ex3.Canti2D.analyze.Dynamic.EQ.Uniform.tcl.txt
Normal file
147
examples/data/Ex3.Canti2D.analyze.Dynamic.EQ.Uniform.tcl.txt
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 3. 2D Cantilever -- EQ ground motion
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
# execute this file after you have built the model, and after you apply gravity
|
||||
#
|
||||
|
||||
# Uniform Earthquake ground motion (uniform acceleration input at all support nodes)
|
||||
set GMdirection 1; # ground-motion direction
|
||||
set GMfile "BM68elc.acc" ; # ground-motion filenames
|
||||
set GMfact 1.5; # ground-motion scaling factor
|
||||
|
||||
# set up ground-motion-analysis parameters
|
||||
set DtAnalysis [expr 0.01*$sec]; # time-step Dt for lateral analysis
|
||||
set TmaxAnalysis [expr 10. *$sec]; # maximum duration of ground-motion analysis -- should be 50*$sec
|
||||
|
||||
# DYNAMIC ANALYSIS PARAMETERS
|
||||
# CONSTRAINTS handler -- Determines how the constraint equations are enforced in the analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/617.htm)
|
||||
# Plain Constraints -- Removes constrained degrees of freedom from the system of equations
|
||||
# Lagrange Multipliers -- Uses the method of Lagrange multipliers to enforce constraints
|
||||
# Penalty Method -- Uses penalty numbers to enforce constraints
|
||||
# Transformation Method -- Performs a condensation of constrained degrees of freedom
|
||||
constraints Transformation ;
|
||||
|
||||
# DOF NUMBERER (number the degrees of freedom in the domain): (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/366.htm)
|
||||
# determines the mapping between equation numbers and degrees-of-freedom
|
||||
# Plain -- Uses the numbering provided by the user
|
||||
# RCM -- Renumbers the DOF to minimize the matrix band-width using the Reverse Cuthill-McKee algorithm
|
||||
numberer Plain
|
||||
|
||||
# SYSTEM (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/371.htm)
|
||||
# Linear Equation Solvers (how to store and solve the system of equations in the analysis)
|
||||
# -- provide the solution of the linear system of equations Ku = P. Each solver is tailored to a specific matrix topology.
|
||||
# ProfileSPD -- Direct profile solver for symmetric positive definite matrices
|
||||
# BandGeneral -- Direct solver for banded unsymmetric matrices
|
||||
# BandSPD -- Direct solver for banded symmetric positive definite matrices
|
||||
# SparseGeneral -- Direct solver for unsymmetric sparse matrices (-piv option)
|
||||
# SparseSPD -- Direct solver for symmetric sparse matrices
|
||||
# UmfPack -- Direct UmfPack solver for unsymmetric matrices
|
||||
system SparseGeneral -piv
|
||||
|
||||
# TEST: # convergence test to
|
||||
# Convergence TEST (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/360.htm)
|
||||
# -- Accept the current state of the domain as being on the converged solution path
|
||||
# -- determine if convergence has been achieved at the end of an iteration step
|
||||
# NormUnbalance -- Specifies a tolerance on the norm of the unbalanced load at the current iteration
|
||||
# NormDispIncr -- Specifies a tolerance on the norm of the displacement increments at the current iteration
|
||||
# EnergyIncr-- Specifies a tolerance on the inner product of the unbalanced load and displacement increments at the current iteration
|
||||
# RelativeNormUnbalance --
|
||||
# RelativeNormDispIncr --
|
||||
# RelativeEnergyIncr --
|
||||
set Tol 1.e-8; # Convergence Test: tolerance
|
||||
set maxNumIter 10; # Convergence Test: maximum number of iterations that will be performed before "failure to converge" is returned
|
||||
set printFlag 0; # Convergence Test: flag used to print information on convergence (optional) # 1: print information on each step;
|
||||
set TestType EnergyIncr; # Convergence-test type
|
||||
test $TestType $Tol $maxNumIter $printFlag;
|
||||
|
||||
# Solution ALGORITHM: -- Iterate from the last time step to the current (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/682.htm)
|
||||
# Linear -- Uses the solution at the first iteration and continues
|
||||
# Newton -- Uses the tangent at the current iteration to iterate to convergence
|
||||
# ModifiedNewton -- Uses the tangent at the first iteration to iterate to convergence
|
||||
# NewtonLineSearch --
|
||||
# KrylovNewton --
|
||||
# BFGS --
|
||||
# Broyden --
|
||||
set algorithmType ModifiedNewton
|
||||
algorithm $algorithmType;
|
||||
|
||||
# Static INTEGRATOR: -- determine the next time step for an analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/689.htm)
|
||||
# LoadControl -- Specifies the incremental load factor to be applied to the loads in the domain
|
||||
# DisplacementControl -- Specifies the incremental displacement at a specified DOF in the domain
|
||||
# Minimum Unbalanced Displacement Norm -- Specifies the incremental load factor such that the residual displacement norm in minimized
|
||||
# Arc Length -- Specifies the incremental arc-length of the load-displacement path
|
||||
# Transient INTEGRATOR: -- determine the next time step for an analysis including inertial effects
|
||||
# Newmark -- The two parameter time-stepping method developed by Newmark
|
||||
# HHT -- The three parameter Hilbert-Hughes-Taylor time-stepping method
|
||||
# Central Difference -- Approximates velocity and acceleration by centered finite differences of displacement
|
||||
set NewmarkGamma 0.5; # Newmark-integrator gamma parameter (also HHT)
|
||||
set NewmarkBeta 0.25; # Newmark-integrator beta parameter
|
||||
integrator Newmark $NewmarkGamma $NewmarkBeta
|
||||
|
||||
# ANALYSIS -- defines what type of analysis is to be performed (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/324.htm)
|
||||
# Static Analysis -- solves the KU=R problem, without the mass or damping matrices.
|
||||
# Transient Analysis -- solves the time-dependent analysis. The time step in this type of analysis is constant. The time step in the output is also constant.
|
||||
# variableTransient Analysis -- performs the same analysis type as the Transient Analysis object. The time step, however, is variable. This method is used when
|
||||
# there are convergence problems with the Transient Analysis object at a peak or when the time step is too small. The time step in the output is also variable.
|
||||
analysis Transient
|
||||
|
||||
# define DAMPING--------------------------------------------------------------------------------------
|
||||
# apply Rayleigh DAMPING from $xDamp
|
||||
# D=$alphaM*M + $betaKcurr*Kcurrent + $betaKcomm*KlastCommit + $beatKinit*$Kinitial
|
||||
set xDamp 0.02; # 2% damping ratio
|
||||
set lambda [eigen 1]; # eigenvalue mode 1
|
||||
set omega [expr pow($lambda,0.5)];
|
||||
set alphaM 0.; # M-prop. damping; D = alphaM*M
|
||||
set betaKcurr 0.; # K-proportional damping; +beatKcurr*KCurrent
|
||||
set betaKcomm [expr 2.*$xDamp/($omega)]; # K-prop. damping parameter; +betaKcomm*KlastCommitt
|
||||
set betaKinit 0.; # initial-stiffness proportional damping +beatKinit*Kini
|
||||
# define damping
|
||||
rayleigh $alphaM $betaKcurr $betaKinit $betaKcomm; # RAYLEIGH damping
|
||||
|
||||
# --------------------------------- perform Dynamic Ground-Motion Analysis
|
||||
# Uniform EXCITATION: acceleration input
|
||||
set IDloadTag 400; # load tag
|
||||
set dt 0.01; # time step for input ground motion
|
||||
set GMfatt 1.0; # data in input file is in g Unifts -- ACCELERATION TH
|
||||
set AccelSeries "Series -dt $dt -filePath $GMfile -factor $GMfatt"; # time series information
|
||||
pattern UniformExcitation $IDloadTag $GMdirection -accel $AccelSeries ; # create Unifform excitation
|
||||
|
||||
set Nsteps [expr int($TmaxAnalysis/$DtAnalysis)];
|
||||
set ok [analyze $Nsteps $DtAnalysis]; # actually perform analysis; returns ok=0 if analysis was successful
|
||||
|
||||
if {$ok != 0} { ; # if analysis was not successful.
|
||||
# change some analysis parameters to achieve convergence
|
||||
# performance is slower inside this loop
|
||||
# Time-controlled analysis
|
||||
set ok 0;
|
||||
set controlTime [getTime];
|
||||
while {$controlTime < $TmaxAnalysis && $ok == 0} {
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
set controlTime [getTime]
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 1000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
test $TestType $Tol $maxNumIter 0
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
}
|
||||
}; # end if ok !0
|
||||
|
||||
|
||||
|
||||
puts "Ground Motion Done. End Time: [getTime]"
|
||||
119
examples/data/Ex3.Canti2D.analyze.Static.Push.tcl.txt
Normal file
119
examples/data/Ex3.Canti2D.analyze.Static.Push.tcl.txt
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 3. 2D Cantilever -- Static Pushover
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
# execute this file after you have built the model, and after you apply gravity
|
||||
#
|
||||
|
||||
# characteristics of pushover analysis
|
||||
set Dmax [expr 0.05*$LCol]; # maximum displacement of pushover. push to 10% drift.
|
||||
set Dincr [expr 0.001*$LCol]; # displacement increment for pushover. you want this to be very small, but not too small to slow down the analysis
|
||||
|
||||
# create load pattern for lateral pushover load
|
||||
set Hload [expr $Weight]; # define the lateral load as a proportion of the weight so that the pseudo time equals the lateral-load coefficient when using linear load pattern
|
||||
pattern Plain 200 Linear {; # define load pattern -- generalized
|
||||
load 2 $Hload 0.0 0.0 0.0 0.0 0.0
|
||||
}
|
||||
|
||||
# STATIC-ANALYSIS parameters
|
||||
# CONSTRAINTS handler -- Determines how the constraint equations are enforced in the analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/617.htm)
|
||||
# Plain Constraints -- Removes constrained degrees of freedom from the system of equations (only for homogeneous equations)
|
||||
# Lagrange Multipliers -- Uses the method of Lagrange multipliers to enforce constraints
|
||||
# Penalty Method -- Uses penalty numbers to enforce constraints --good for static analysis with non-homogeneous eqns (rigidDiaphragm)
|
||||
# Transformation Method -- Performs a condensation of constrained degrees of freedom
|
||||
set constraintsType Plain; # default;
|
||||
constraints $constraintsType
|
||||
|
||||
# DOF NUMBERER (number the degrees of freedom in the domain): (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/366.htm)
|
||||
# determines the mapping between equation numbers and degrees-of-freedom
|
||||
# Plain -- Uses the numbering provided by the user
|
||||
# RCM -- Renumbers the DOF to minimize the matrix band-width using the Reverse Cuthill-McKee algorithm
|
||||
numberer Plain
|
||||
|
||||
# SYSTEM (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/371.htm)
|
||||
# Linear Equation Solvers (how to store and solve the system of equations in the analysis)
|
||||
# -- provide the solution of the linear system of equations Ku = P. Each solver is tailored to a specific matrix topology.
|
||||
# ProfileSPD -- Direct profile solver for symmetric positive definite matrices
|
||||
# BandGeneral -- Direct solver for banded unsymmetric matrices
|
||||
# BandSPD -- Direct solver for banded symmetric positive definite matrices
|
||||
# SparseGeneral -- Direct solver for unsymmetric sparse matrices
|
||||
# SparseSPD -- Direct solver for symmetric sparse matrices
|
||||
# UmfPack -- Direct UmfPack solver for unsymmetric matrices
|
||||
system BandGeneral
|
||||
|
||||
# TEST: # convergence test to
|
||||
# Convergence TEST (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/360.htm)
|
||||
# -- Accept the current state of the domain as being on the converged solution path
|
||||
# -- determine if convergence has been achieved at the end of an iteration step
|
||||
# NormUnbalance -- Specifies a tolerance on the norm of the unbalanced load at the current iteration
|
||||
# NormDispIncr -- Specifies a tolerance on the norm of the displacement increments at the current iteration
|
||||
# EnergyIncr-- Specifies a tolerance on the inner product of the unbalanced load and displacement increments at the current iteration
|
||||
set Tol 1.e-8; # Convergence Test: tolerance
|
||||
set maxNumIter 6; # Convergence Test: maximum number of iterations that will be performed before "failure to converge" is returned
|
||||
set printFlag 0; # Convergence Test: flag used to print information on convergence (optional) # 1: print information on each step;
|
||||
set TestType EnergyIncr; # Convergence-test type
|
||||
test $TestType $Tol $maxNumIter $printFlag;
|
||||
|
||||
# Solution ALGORITHM: -- Iterate from the last time step to the current (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/682.htm)
|
||||
# Linear -- Uses the solution at the first iteration and continues
|
||||
# Newton -- Uses the tangent at the current iteration to iterate to convergence
|
||||
# ModifiedNewton -- Uses the tangent at the first iteration to iterate to convergence
|
||||
set algorithmType Newton
|
||||
algorithm $algorithmType;
|
||||
|
||||
# Static INTEGRATOR: -- determine the next time step for an analysis (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/689.htm)
|
||||
# LoadControl -- Specifies the incremental load factor to be applied to the loads in the domain
|
||||
# DisplacementControl -- Specifies the incremental displacement at a specified DOF in the domain
|
||||
# Minimum Unbalanced Displacement Norm -- Specifies the incremental load factor such that the residual displacement norm in minimized
|
||||
# Arc Length -- Specifies the incremental arc-length of the load-displacement path
|
||||
# Transient INTEGRATOR: -- determine the next time step for an analysis including inertial effects
|
||||
# Newmark -- The two parameter time-stepping method developed by Newmark
|
||||
# HHT -- The three parameter Hilbert-Hughes-Taylor time-stepping method
|
||||
# Central Difference -- Approximates velocity and acceleration by centered finite differences of displacement
|
||||
integrator DisplacementControl $IDctrlNode $IDctrlDOF $Dincr
|
||||
|
||||
# ANALYSIS -- defines what type of analysis is to be performed (http://opensees.berkeley.edu/OpenSees/manuals/usermanual/324.htm)
|
||||
# Static Analysis -- solves the KU=R problem, without the mass or damping matrices.
|
||||
# Transient Analysis -- solves the time-dependent analysis. The time step in this type of analysis is constant. The time step in the output is also constant.
|
||||
# variableTransient Analysis -- performs the same analysis type as the Transient Analysis object. The time step, however, is variable. This method is used when
|
||||
# there are convergence problems with the Transient Analysis object at a peak or when the time step is too small. The time step in the output is also variable.
|
||||
analysis Static
|
||||
|
||||
|
||||
# --------------------------------- perform Static Pushover Analysis
|
||||
set Nsteps [expr int($Dmax/$Dincr)]; # number of pushover analysis steps
|
||||
set ok [analyze $Nsteps]; # this will return zero if no convergence problems were encountered
|
||||
|
||||
if {$ok != 0} {
|
||||
# if analysis fails, we try some other stuff, performance is slower inside this loop
|
||||
set ok 0;
|
||||
set controlDisp 0.0;
|
||||
set D0 0.0; # analysis starts from zero
|
||||
set Dstep [expr ($controlDisp-$D0)/($Dmax-$D0)]
|
||||
while {$Dstep < 1.0 && $ok == 0} {
|
||||
set controlDisp [nodeDisp $IDctrlNode $IDctrlDOF ]
|
||||
set Dstep [expr ($controlDisp-$D0)/($Dmax-$D0)]
|
||||
set ok [analyze 1 ]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 2000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 ]
|
||||
test $TestType $Tol $maxNumIter 0
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmType
|
||||
}
|
||||
}; # end while loop
|
||||
}; # end if ok !0
|
||||
|
||||
puts "Pushover Done. Control Disp=[nodeDisp $IDctrlNode $IDctrlDOF]"
|
||||
116
examples/data/Ex3.Canti2D.build.ElasticElement.tcl.txt
Normal file
116
examples/data/Ex3.Canti2D.build.ElasticElement.tcl.txt
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 3. 2D Cantilever -- Build Model
|
||||
# elasticBeamColumn element
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear memory of all past model definitions
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
set dataDir Data; # set up name for data directory
|
||||
file mkdir $dataDir/; # create data directory
|
||||
set GMdir "../GMfiles"; # ground-motion file directory
|
||||
|
||||
# define UNITS ----------------------------------------------------------------------------
|
||||
set in 1.; # define basic units -- output units
|
||||
set kip 1.; # define basic units -- output units
|
||||
set sec 1.; # define basic units -- output units
|
||||
set LunitTXT "inch"; # define basic-unit text for output
|
||||
set FunitTXT "kip"; # define basic-unit text for output
|
||||
set TunitTXT "sec"; # define basic-unit text for output
|
||||
set ft [expr 12.*$in]; # define engineering units
|
||||
set ksi [expr $kip/pow($in,2)];
|
||||
set psi [expr $ksi/1000.];
|
||||
set lbf [expr $psi*$in*$in]; # pounds force
|
||||
set pcf [expr $lbf/pow($ft,3)]; # pounds per cubic foot
|
||||
set in2 [expr $in*$in]; # inch^2
|
||||
set in4 [expr $in*$in*$in*$in]; # inch^4
|
||||
set cm [expr $in/2.54]; # centimeter, needed for displacement input in MultipleSupport excitation
|
||||
set PI [expr 2*asin(1.0)]; # define constants
|
||||
set g [expr 32.2*$ft/pow($sec,2)]; # gravitational acceleration
|
||||
set Ubig 1.e10; # a really large number
|
||||
set Usmall [expr 1/$Ubig]; # a really small number
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol [expr 36*$ft]; # column length
|
||||
set Weight [expr 2000.*$kip]; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol [expr 5.*$ft]; # Column Depth
|
||||
set BCol [expr 5.*$ft]; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol [expr $Weight]; # nodal dead-load weight per column
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol]; # cross-sectional area
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# we need to set up parameters that are particular to the model.
|
||||
set IDctrlNode 2; # node where displacement is read for displacement control
|
||||
set IDctrlDOF 1; # degree of freedom of displacement read for displacement control
|
||||
set iSupportNode "1"; # define support node, if needed.
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# Material parameters
|
||||
set fc [expr -4.*$ksi]; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*$ksi*sqrt(-$fc/$psi)]; # Concrete Elastic Modulus
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
set ColTransfType Linear ; # options, Linear PDelta Corotational
|
||||
geomTransf $ColTransfType $ColTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
element elasticBeamColumn 1 1 2 $ACol $Ec $IzCol $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file $dataDir/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file $dataDir/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file $dataDir/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file $dataDir/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file $dataDir/FCol.out -time -ele 1 globalForce; # element forces -- column
|
||||
recorder Element -xml $dataDir/PlasticRotation.out -time -ele 1 plasticRotation; # section deformations, axial and curvature, node j
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------- apply gravity load
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
179
examples/data/Ex3.Canti2D.build.InelasticFiberSection.tcl.txt
Normal file
179
examples/data/Ex3.Canti2D.build.InelasticFiberSection.tcl.txt
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 3. 2D Cantilever -- Build Model
|
||||
# nonlinearBeamColumn element, uniaxial inelastic section
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear memory of all past model definitions
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
set dataDir Data; # set up name for data directory
|
||||
file mkdir $dataDir/; # create data directory
|
||||
set GMdir "../GMfiles"; # ground-motion file directory
|
||||
|
||||
# define UNITS ----------------------------------------------------------------------------
|
||||
set in 1.; # define basic units -- output units
|
||||
set kip 1.; # define basic units -- output units
|
||||
set sec 1.; # define basic units -- output units
|
||||
set LunitTXT "inch"; # define basic-unit text for output
|
||||
set FunitTXT "kip"; # define basic-unit text for output
|
||||
set TunitTXT "sec"; # define basic-unit text for output
|
||||
set ft [expr 12.*$in]; # define engineering units
|
||||
set ksi [expr $kip/pow($in,2)];
|
||||
set psi [expr $ksi/1000.];
|
||||
set lbf [expr $psi*$in*$in]; # pounds force
|
||||
set pcf [expr $lbf/pow($ft,3)]; # pounds per cubic foot
|
||||
set in2 [expr $in*$in]; # inch^2
|
||||
set in4 [expr $in*$in*$in*$in]; # inch^4
|
||||
set cm [expr $in/2.54]; # centimeter, needed for displacement input in MultipleSupport excitation
|
||||
set PI [expr 2*asin(1.0)]; # define constants
|
||||
set g [expr 32.2*$ft/pow($sec,2)]; # gravitational acceleration
|
||||
set Ubig 1.e10; # a really large number
|
||||
set Usmall [expr 1/$Ubig]; # a really small number
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol [expr 36*$ft]; # column length
|
||||
set Weight [expr 2000.*$kip]; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol [expr 5.*$ft]; # Column Depth
|
||||
set BCol [expr 5.*$ft]; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol [expr $Weight]; # nodal dead-load weight per column
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol]; # cross-sectional area
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# we need to set up parameters that are particular to the model.
|
||||
set IDctrlNode 2; # node where displacement is read for displacement control
|
||||
set IDctrlDOF 1; # degree of freedom of displacement read for displacement control
|
||||
set iSupportNode "1"; # define support node, if needed.
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS & SECTIONS -------------------------------------------------------------
|
||||
set ColSecTag 1; # assign a tag number to the column section
|
||||
# define section geometry
|
||||
set coverCol [expr 5.*$in]; # Column cover to reinforcing steel NA.
|
||||
set numBarsCol 20; # number of longitudinal-reinforcement bars in column. (symmetric top & bot)
|
||||
set barAreaCol [expr 2.25*$in2]; # area of longitudinal-reinforcement bars
|
||||
|
||||
|
||||
# MATERIAL parameters -------------------------------------------------------------------
|
||||
set IDconcU 1; # material ID tag -- unconfined cover concrete
|
||||
set IDreinf 2; # material ID tag -- reinforcement
|
||||
# nominal concrete compressive strength
|
||||
set fc [expr -4.0*$ksi]; # CONCRETE Compressive Strength, ksi (+Tension, -Compression)
|
||||
set Ec [expr 57*$ksi*sqrt(-$fc/$psi)]; # Concrete Elastic Modulus
|
||||
# unconfined concrete
|
||||
set fc1U $fc; # UNCONFINED concrete (todeschini parabolic model), maximum stress
|
||||
set eps1U -0.003; # strain at maximum strength of unconfined concrete
|
||||
set fc2U [expr 0.2*$fc1U]; # ultimate stress
|
||||
set eps2U -0.01; # strain at ultimate stress
|
||||
set lambda 0.1; # ratio between unloading slope at $eps2 and initial slope $Ec
|
||||
# tensile-strength properties
|
||||
set ftU [expr -0.14*$fc1U]; # tensile strength +tension
|
||||
set Ets [expr $ftU/0.002]; # tension softening stiffness
|
||||
# -----------
|
||||
set Fy [expr 66.8*$ksi]; # STEEL yield stress
|
||||
set Es [expr 29000.*$ksi]; # modulus of steel
|
||||
set Bs 0.01; # strain-hardening ratio
|
||||
set R0 18; # control the transition from elastic to plastic branches
|
||||
set cR1 0.925; # control the transition from elastic to plastic branches
|
||||
set cR2 0.15; # control the transition from elastic to plastic branches
|
||||
uniaxialMaterial Concrete02 $IDconcU $fc1U $eps1U $fc2U $eps2U $lambda $ftU $Ets; # build cover concrete (unconfined)
|
||||
uniaxialMaterial Steel02 $IDreinf $Fy $Es $Bs $R0 $cR1 $cR2; # build reinforcement material
|
||||
|
||||
# FIBER SECTION properties -------------------------------------------------------------
|
||||
# symmetric section
|
||||
# y
|
||||
# ^
|
||||
# |
|
||||
# --------------------- -- --
|
||||
# | o o o | | -- cover
|
||||
# | | |
|
||||
# | | |
|
||||
# z <--- | + | H
|
||||
# | | |
|
||||
# | | |
|
||||
# | o o o | | -- cover
|
||||
# --------------------- -- --
|
||||
# |-------- B --------|
|
||||
#
|
||||
# RC section:
|
||||
set coverY [expr $HCol/2.0]; # The distance from the section z-axis to the edge of the cover concrete -- outer edge of cover concrete
|
||||
set coverZ [expr $BCol/2.0]; # The distance from the section y-axis to the edge of the cover concrete -- outer edge of cover concrete
|
||||
set coreY [expr $coverY-$coverCol]
|
||||
set coreZ [expr $coverZ-$coverCol]
|
||||
set nfY 16; # number of fibers for concrete in y-direction
|
||||
set nfZ 4; # number of fibers for concrete in z-direction
|
||||
section fiberSec $ColSecTag {; # Define the fiber section
|
||||
patch quadr $IDconcU $nfZ $nfY -$coverY $coverZ -$coverY -$coverZ $coverY -$coverZ $coverY $coverZ; # Define the concrete patch
|
||||
layer straight $IDreinf $numBarsCol $barAreaCol -$coreY $coreZ -$coreY -$coreZ; # top layer reinfocement
|
||||
layer straight $IDreinf $numBarsCol $barAreaCol $coreY $coreZ $coreY -$coreZ; # bottom layer reinforcement
|
||||
}; # end of fibersection definition
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
set ColTransfType Linear ; # options, Linear PDelta Corotational
|
||||
geomTransf $ColTransfType $ColTransfTag ;
|
||||
|
||||
|
||||
# element connectivity:
|
||||
set numIntgrPts 5; # number of integration points for force-based element
|
||||
element nonlinearBeamColumn 1 1 2 $numIntgrPts $ColSecTag $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file $dataDir/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file $dataDir/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file $dataDir/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file $dataDir/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file $dataDir/FCol.out -time -ele 2 globalForce; # element forces -- column
|
||||
recorder Element -file $dataDir/ForceColSec1.out -time -ele 1 section 1 force; # Column section forces, axial and moment, node i
|
||||
recorder Element -file $dataDir/DefoColSec1.out -time -ele 1 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file $dataDir/ForceColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file $dataDir/DefoColSec$numIntgrPts.out -time -ele 1 section 1 deformation; # section deformations, axial and curvature, node j
|
||||
recorder Element -xml $dataDir/PlasticRotation.out -time -ele 1 plasticRotation; # section deformations, axial and curvature, node j
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# Gravity-analysis parameters -- load-controlled static analysis
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
139
examples/data/Ex3.Canti2D.build.InelasticSection.tcl.txt
Normal file
139
examples/data/Ex3.Canti2D.build.InelasticSection.tcl.txt
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example 3. 2D Cantilever -- Build Model
|
||||
# nonlinearBeamColumn element, inelastic fiber section
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 2 __
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# (1) LCol
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# =1= _|_ -------->X
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear memory of all past model definitions
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
set dataDir Data; # set up name for data directory
|
||||
file mkdir $dataDir/; # create data directory
|
||||
set GMdir "../GMfiles"; # ground-motion file directory
|
||||
|
||||
# define UNITS ----------------------------------------------------------------------------
|
||||
set in 1.; # define basic units -- output units
|
||||
set kip 1.; # define basic units -- output units
|
||||
set sec 1.; # define basic units -- output units
|
||||
set LunitTXT "inch"; # define basic-unit text for output
|
||||
set FunitTXT "kip"; # define basic-unit text for output
|
||||
set TunitTXT "sec"; # define basic-unit text for output
|
||||
set ft [expr 12.*$in]; # define engineering units
|
||||
set ksi [expr $kip/pow($in,2)];
|
||||
set psi [expr $ksi/1000.];
|
||||
set lbf [expr $psi*$in*$in]; # pounds force
|
||||
set pcf [expr $lbf/pow($ft,3)]; # pounds per cubic foot
|
||||
set in2 [expr $in*$in]; # inch^2
|
||||
set in4 [expr $in*$in*$in*$in]; # inch^4
|
||||
set cm [expr $in/2.54]; # centimeter, needed for displacement input in MultipleSupport excitation
|
||||
set PI [expr 2*asin(1.0)]; # define constants
|
||||
set g [expr 32.2*$ft/pow($sec,2)]; # gravitational acceleration
|
||||
set Ubig 1.e10; # a really large number
|
||||
set Usmall [expr 1/$Ubig]; # a really small number
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol [expr 36*$ft]; # column length
|
||||
set Weight [expr 2000.*$kip]; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol [expr 5.*$ft]; # Column Depth
|
||||
set BCol [expr 5.*$ft]; # Column Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol [expr $Weight]; # nodal dead-load weight per column
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol]; # cross-sectional area
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 0 $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 1; # node DX DY RZ
|
||||
|
||||
# we need to set up parameters that are particular to the model.
|
||||
set IDctrlNode 2; # node where displacement is read for displacement control
|
||||
set IDctrlDOF 1; # degree of freedom of displacement read for displacement control
|
||||
set iSupportNode "1"; # define support node, if needed.
|
||||
|
||||
# nodal masses:
|
||||
mass 2 $Mass 1e-9 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
|
||||
# Define ELEMENTS & SECTIONS -------------------------------------------------------------
|
||||
set ColMatTagFlex 2; # assign a tag number to the column flexural behavior
|
||||
set ColMatTagAxial 3; # assign a tag number to the column axial behavior
|
||||
set ColSecTag 1; # assign a tag number to the column section tag
|
||||
set BeamSecTag 2; # assign a tag number to the beam section tag
|
||||
|
||||
# MATERIAL parameters
|
||||
set fc [expr -4*$ksi]; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*$ksi*sqrt(-$fc/$psi)]; # Concrete Elastic Modulus
|
||||
|
||||
# COLUMN section
|
||||
# calculated stiffness parameters
|
||||
set EICol [expr $Ec*$IzCol]; # EI, for moment-curvature relationship
|
||||
set EACol [expr $Ec*$ACol]; # EA, for axial-force-strain relationship
|
||||
set MyCol [expr 130000*$kip*$in]; # yield moment
|
||||
set PhiYCol [expr 0.65e-4/$in]; # yield curvature
|
||||
set EIColCrack [expr $MyCol/$PhiYCol]; # cracked section inertia
|
||||
set b 0.01 ; # strain-hardening ratio (ratio between post-yield tangent and initial elastic tangent)
|
||||
uniaxialMaterial Steel01 $ColMatTagFlex $MyCol $EIColCrack $b; # bilinear behavior for flexure
|
||||
uniaxialMaterial Elastic $ColMatTagAxial $EACol; # this is not used as a material, this is an axial-force-strain response
|
||||
section Aggregator $ColSecTag $ColMatTagAxial P $ColMatTagFlex Mz; # combine axial and flexural behavior into one section (no P-M interaction here)
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
set ColTransfType Linear ; # options, Linear PDelta Corotational
|
||||
geomTransf $ColTransfType $ColTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
set numIntgrPts 5; # number of integration points for force-based element
|
||||
element nonlinearBeamColumn 1 1 2 $numIntgrPts $ColSecTag $ColTransfTag; # self-explanatory when using variables
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file $dataDir/DFree.out -time -node 2 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file $dataDir/DBase.out -time -node 1 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file $dataDir/RBase.out -time -node 1 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file Data/Drift.out -time -iNode 1 -jNode 2 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file $dataDir/FCol.out -time -ele 2 globalForce; # element forces -- column
|
||||
recorder Element -file $dataDir/ForceColSec1.out -time -ele 1 section 1 force; # Column section forces, axial and moment, node i
|
||||
recorder Element -file $dataDir/DefoColSec1.out -time -ele 1 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file $dataDir/ForceColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file $dataDir/DefoColSec$numIntgrPts.out -time -ele 1 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
recorder Element -xml $dataDir/PlasticRotation.out -time -ele 1 plasticRotation; # section deformations, axial and curvature, node j
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
pattern Plain 1 Linear {
|
||||
load 2 0 -$PCol 0
|
||||
}
|
||||
|
||||
# Gravity-analysis parameters -- load-controlled static analysis
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example4. 2D Portal Frame-- Dynamic sine-wave input analysis
|
||||
# Silvia Mazzoni, 2006
|
||||
# execute this file after you have built the model, and after you apply gravity
|
||||
#
|
||||
|
||||
# Uniform Sine-Wave ground motion (uniform acceleration input at all support nodes)
|
||||
set GMdirection 1; # ground-motion direction
|
||||
set GMSineAccAmpl [expr 0.5*$g]; # sine ground-motion acceleration amplitude (this is the support motion, not the free-node motion)
|
||||
set TPeriodSine [expr 0.35*$sec]; # period of input sine wave
|
||||
set DurationSine [expr 3.*$sec]; # duration of input sine wave
|
||||
|
||||
# set up ground-motion-analysis parameters
|
||||
set DtAnalysis [expr 0.01*$sec]; # time-step Dt for lateral analysis
|
||||
set TmaxAnalysis [expr 10. *$sec]; # maximum duration of ground-motion analysis -- should be 50*$sec
|
||||
|
||||
# ----------- set up analysis parameters
|
||||
source LibAnalysisDynamicParameters.tcl; # constraintsHandler,DOFnumberer,system-ofequations,convergenceTest,solutionAlgorithm,integrator
|
||||
|
||||
# define DAMPING--------------------------------------------------------------------------------------
|
||||
# apply Rayleigh DAMPING from $xDamp
|
||||
# D=$alphaM*M + $betaKcurr*Kcurrent + $betaKcomm*KlastCommit + $beatKinit*$Kinitial
|
||||
set xDamp 0.02; # 2% damping ratio
|
||||
set lambda [eigen 1]; # eigenvalue mode 1
|
||||
set omega [expr pow($lambda,0.5)];
|
||||
set alphaM 0.; # M-prop. damping; D = alphaM*M
|
||||
set betaKcurr 0.; # K-proportional damping; +beatKcurr*KCurrent
|
||||
set betaKcomm [expr 2.*$xDamp/($omega)]; # K-prop. damping parameter; +betaKcomm*KlastCommitt
|
||||
set betaKinit 0.; # initial-stiffness proportional damping +beatKinit*Kini
|
||||
rayleigh $alphaM $betaKcurr $betaKinit $betaKcomm; # RAYLEIGH damping
|
||||
|
||||
# --------------------------------- perform Dynamic Ground-Motion Analysis
|
||||
# the following commands are unique to the Sine-Wave excitation
|
||||
set IDloadTag 400; # for uniformSupport excitation
|
||||
set DtGround [expr 0.005*$sec]; # time-step Dt for input grond motion
|
||||
set omegaSine [expr 2*$PI/$TPeriodSine];
|
||||
set vel0 [expr $GMSineAccAmpl*(-1)/$omegaSine];
|
||||
set AccelSeries "Sine 0. $DurationSine $TPeriodSine -factor $GMSineAccAmpl "
|
||||
pattern UniformExcitation $IDloadTag $GMdirection -accel $AccelSeries -vel0 $vel0
|
||||
|
||||
set Nsteps [expr int($TmaxAnalysis/$DtAnalysis)];
|
||||
set ok [analyze $Nsteps $DtAnalysis]; # actually perform analysis; returns ok=0 if analysis was successful
|
||||
|
||||
if {$ok != 0} { ; # analysis was not successful.
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# change some analysis parameters to achieve convergence
|
||||
# performance is slower inside this loop
|
||||
# Time-controlled analysis
|
||||
set ok 0;
|
||||
set controlTime [getTime];
|
||||
while {$controlTime < $TmaxAnalysis && $ok == 0} {
|
||||
set controlTime [getTime]
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 1000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
test $testTypeDynamic $TolDynamic $maxNumIterDynamic 0
|
||||
algorithm $algorithmTypeDynamic
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmTypeDynamic
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch .8
|
||||
set ok [analyze 1 $DtAnalysis]
|
||||
algorithm $algorithmTypeDynamic
|
||||
}
|
||||
}
|
||||
}; # end if ok !0
|
||||
|
||||
|
||||
puts "Ground Motion Done. End Time: [getTime]"
|
||||
69
examples/data/Ex4.Portal2D.analyze.Static.Push.tcl.txt
Normal file
69
examples/data/Ex4.Portal2D.analyze.Static.Push.tcl.txt
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example4. 2D Portal Frame-- Static Pushover Analysis
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
# execute this file after you have built the model, and after you apply gravity
|
||||
#
|
||||
|
||||
# we need to set up parameters that are particular to the model.
|
||||
set IDctrlNode 3; # node where displacement is read for displacement control
|
||||
set IDctrlDOF 1; # degree of freedom of displacement read for displacement contro
|
||||
# characteristics of pushover analysis
|
||||
set Dmax [expr 0.1*$LCol]; # maximum displacement of pushover. push to 10% drift.
|
||||
set Dincr [expr 0.001*$LCol]; # displacement increment for pushover. you want this to be very small, but not too small to slow down the analysis
|
||||
|
||||
# create load pattern for lateral pushover load
|
||||
set Hload [expr $Weight/2]; # define the lateral load as a proportion of the weight so that the pseudo time equals the lateral-load coefficient when using linear load pattern
|
||||
set iPushNode "3 4"; # define nodes where lateral load is applied in static lateral analysis
|
||||
pattern Plain 200 Linear {; # define load pattern -- generalized
|
||||
foreach PushNode $iPushNode {
|
||||
load $PushNode $Hload 0.0 0.0 0.0 0.0 0.0
|
||||
}
|
||||
}
|
||||
|
||||
# ----------- set up analysis parameters
|
||||
source LibAnalysisStaticParameters.tcl; # constraintsHandler,DOFnumberer,system-ofequations,convergenceTest,solutionAlgorithm,integrator
|
||||
|
||||
# --------------------------------- perform Static Pushover Analysis
|
||||
set Nsteps [expr int($Dmax/$Dincr)]; # number of pushover analysis steps
|
||||
set ok [analyze $Nsteps]; # this will return zero if no convergence problems were encountered
|
||||
set fmt1 "%s Pushover analysis: CtrlNode %.3i, dof %.1i, Disp=%.4f %s"; # format for screen/file output of DONE/PROBLEM analysis
|
||||
if {$ok != 0} {
|
||||
# if analysis fails, we try some other stuff, performance is slower inside this loop
|
||||
set Dstep 0.0;
|
||||
set ok 0
|
||||
while {$Dstep <= 1.0 && $ok == 0} {
|
||||
set controlDisp [nodeDisp $IDctrlNode $IDctrlDOF ]
|
||||
set Dstep [expr $controlDisp/$Dmax]
|
||||
set ok [analyze 1 ]
|
||||
# if analysis fails, we try some other stuff
|
||||
# performance is slower inside this loop global maxNumIterStatic; # max no. of iterations performed before "failure to converge" is ret'd
|
||||
if {$ok != 0} {
|
||||
puts "Trying Newton with Initial Tangent .."
|
||||
test NormDispIncr $Tol 2000 0
|
||||
algorithm Newton -initial
|
||||
set ok [analyze 1]
|
||||
test $testTypeStatic $TolStatic $maxNumIterStatic 0
|
||||
algorithm $algorithmTypeStatic
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying Broyden .."
|
||||
algorithm Broyden 8
|
||||
set ok [analyze 1 ]
|
||||
algorithm $algorithmTypeStatic
|
||||
}
|
||||
if {$ok != 0} {
|
||||
puts "Trying NewtonWithLineSearch .."
|
||||
algorithm NewtonLineSearch 0.8
|
||||
set ok [analyze 1]
|
||||
algorithm $algorithmTypeStatic
|
||||
}
|
||||
|
||||
}; # end while loop
|
||||
}; # end if ok !0
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------
|
||||
if {$ok != 0 } {
|
||||
puts [format $fmt1 "PROBLEM" $IDctrlNode $IDctrlDOF [nodeDisp $IDctrlNode $IDctrlDOF] $LunitTXT]
|
||||
} else {
|
||||
puts [format $fmt1 "DONE" $IDctrlNode $IDctrlDOF [nodeDisp $IDctrlNode $IDctrlDOF] $LunitTXT]
|
||||
}
|
||||
108
examples/data/Ex4.Portal2D.build.ElasticElement.tcl.txt
Normal file
108
examples/data/Ex4.Portal2D.build.ElasticElement.tcl.txt
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example4. 2D Portal Frame-- Build Model
|
||||
# elasticBeamColumn element
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
# ^Y
|
||||
# |
|
||||
# 3_________(3)________4 __
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# (1) (2) LCol
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# =1= =2= _|_ -------->X
|
||||
# |----------LBeam------------|
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear memory of all past model definitions
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
set dataDir Data; # set up name of data directory
|
||||
file mkdir $dataDir; # create data directory
|
||||
set GMdir "GMfiles"; # ground-motion file directory
|
||||
source LibUnits.tcl; # define basic and system units
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol [expr 36*$ft]; # column length
|
||||
set LBeam [expr 42*$ft]; # beam length
|
||||
set Weight [expr 4000.*$kip]; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol [expr 5.*$ft]; # Column Depth
|
||||
set BCol [expr 4.*$ft]; # Column Width
|
||||
set HBeam [expr 8.*$ft]; # Beam Depth
|
||||
set BBeam [expr 5.*$ft]; # Beam Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol [expr $Weight/2]; # nodal dead-load weight per column
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
set MCol [expr 1./12.*($Weight/$LBeam)*pow($LBeam,2)]; # beam-end moment due to distributed load.
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol]; # cross-sectional area
|
||||
set ABeam [expr $BBeam*$HBeam];
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
set IzBeam [expr 1./12.*$BBeam*pow($HBeam,3)]; # Beam moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 $LBeam 0
|
||||
node 3 0 $LCol
|
||||
node 4 $LBeam $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 0; # node DX DY RZ
|
||||
fix 2 1 1 0; # node DX DY RZ
|
||||
fix 3 0 0 0
|
||||
fix 4 0 0 0
|
||||
|
||||
# nodal masses:
|
||||
mass 3 $Mass 0. 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
mass 4 $Mass 0. 0.
|
||||
|
||||
# Define ELEMENTS -------------------------------------------------------------
|
||||
# Material parameters
|
||||
set fc [expr -4.*$ksi]; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*$ksi*sqrt(-$fc/$psi)]; # Concrete Elastic Modulus
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
set BeamTransfTag 2; # associate a tag to beam transformation (good practice to keep col and beam separate)
|
||||
set ColTransfType Linear ; # options, Linear PDelta Corotational
|
||||
geomTransf $ColTransfType $ColTransfTag ; # only columns can have PDelta effects (gravity effects)
|
||||
geomTransf Linear $BeamTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
element elasticBeamColumn 1 1 3 $ACol $Ec $IzCol $ColTransfTag; # self-explanatory when using variables
|
||||
element elasticBeamColumn 2 2 4 $ACol $Ec $IzCol $ColTransfTag;
|
||||
element elasticBeamColumn 3 3 4 $ABeam $Ec $IzBeam $BeamTransfTag;
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file $dataDir/DFree.out -time -node 3 4 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file $dataDir/DBase.out -time -node 1 2 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file $dataDir/RBase.out -time -node 1 2 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file $dataDir/Drift.out -time -iNode 1 2 -jNode 3 4 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file $dataDir/FCol.out -time -ele 1 2 globalForce; # element forces -- column
|
||||
recorder Element -file $dataDir/FBeam.out -time -ele 3 globalForce; # element forces -- beam
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
set WzBeam [expr $Weight/$LBeam];
|
||||
pattern Plain 1 Linear {
|
||||
eleLoad -ele 3 -type -beamUniform -$WzBeam ; # distributed superstructure-weight on beam
|
||||
}
|
||||
# ------------------------------------------------- apply gravity load
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
178
examples/data/Ex4.Portal2D.build.InelasticFiberSection.tcl.txt
Normal file
178
examples/data/Ex4.Portal2D.build.InelasticFiberSection.tcl.txt
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example4. 2D Portal Frame-- Build Model
|
||||
# nonlinearBeamColumn element, inelastic fiber section
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 3_________(3)________4 __
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# (1) (2) LCol
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# =1= =2= _|_ -------->X
|
||||
# |----------LBeam------------|
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear memory of all past model definitions
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
set dataDir Data; # set up name of data directory
|
||||
file mkdir $dataDir; # create data directory
|
||||
set GMdir "GMfiles"; # ground-motion file directory
|
||||
source LibUnits.tcl; # define basic and system units
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol [expr 36*$ft]; # column length
|
||||
set LBeam [expr 42*$ft]; # beam length
|
||||
set Weight [expr 2000.*$kip]; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol [expr 5.*$ft]; # Column Depth
|
||||
set BCol [expr 5.*$ft]; # Column Width
|
||||
set HBeam [expr 8.*$ft]; # Beam Depth
|
||||
set BBeam [expr 5.*$ft]; # Beam Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol [expr $Weight/2]; # nodal dead-load weight per column
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
set MCol [expr 1./12.*($Weight/$LBeam)*pow($LBeam,2)]; # beam-end moment due to distributed load.
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol]; # cross-sectional area
|
||||
set ABeam [expr $BBeam*$HBeam];
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
set IzBeam [expr 1./12.*$BBeam*pow($HBeam,3)]; # Beam moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 $LBeam 0
|
||||
node 3 0 $LCol
|
||||
node 4 $LBeam $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 0; # node DX DY RZ
|
||||
fix 2 1 1 0; # node DX DY RZ
|
||||
fix 3 0 0 0
|
||||
fix 4 0 0 0
|
||||
|
||||
# nodal masses:
|
||||
mass 3 $Mass 0. 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
mass 4 $Mass 0. 0.
|
||||
|
||||
# Define ELEMENTS & SECTIONS -------------------------------------------------------------
|
||||
set ColSecTag 1; # assign a tag number to the column section
|
||||
set BeamSecTag 2; # assign a tag number to the beam section
|
||||
# define section geometry
|
||||
set coverCol [expr 6.*$in]; # Column cover to reinforcing steel NA.
|
||||
set numBarsCol 10; # number of longitudinal-reinforcement bars in each side of column section. (symmetric top & bot)
|
||||
set barAreaCol [expr 2.25*$in2]; # area of longitudinal-reinforcement bars
|
||||
|
||||
# MATERIAL parameters -------------------------------------------------------------------
|
||||
set IDconcU 1; # material ID tag -- unconfined cover concrete
|
||||
set IDreinf 2; # material ID tag -- reinforcement
|
||||
# nominal concrete compressive strength
|
||||
set fc [expr -4.0*$ksi]; # CONCRETE Compressive Strength, ksi (+Tension, -Compression)
|
||||
set Ec [expr 57*$ksi*sqrt(-$fc/$psi)]; # Concrete Elastic Modulus
|
||||
# unconfined concrete
|
||||
set fc1U $fc; # UNCONFINED concrete (todeschini parabolic model), maximum stress
|
||||
set eps1U -0.003; # strain at maximum strength of unconfined concrete
|
||||
set fc2U [expr 0.2*$fc1U]; # ultimate stress
|
||||
set eps2U -0.05; # strain at ultimate stress
|
||||
set lambda 0.1; # ratio between unloading slope at $eps2 and initial slope $Ec
|
||||
# tensile-strength properties
|
||||
set ftU [expr -0.14*$fc1U]; # tensile strength +tension
|
||||
set Ets [expr $ftU/0.002]; # tension softening stiffness
|
||||
# -----------
|
||||
set Fy [expr 66.8*$ksi]; # STEEL yield stress
|
||||
set Es [expr 29000.*$ksi]; # modulus of steel
|
||||
set Bs 0.01; # strain-hardening ratio
|
||||
set R0 18; # control the transition from elastic to plastic branches
|
||||
set cR1 0.925; # control the transition from elastic to plastic branches
|
||||
set cR2 0.15; # control the transition from elastic to plastic branches
|
||||
uniaxialMaterial Concrete02 $IDconcU $fc1U $eps1U $fc2U $eps2U $lambda $ftU $Ets; # build cover concrete (unconfined)
|
||||
uniaxialMaterial Steel02 $IDreinf $Fy $Es $Bs $R0 $cR1 $cR2; # build reinforcement material
|
||||
|
||||
# FIBER SECTION properties -------------------------------------------------------------
|
||||
# symmetric section
|
||||
# y
|
||||
# ^
|
||||
# |
|
||||
# --------------------- -- --
|
||||
# | o o o | | -- cover
|
||||
# | | |
|
||||
# | | |
|
||||
# z <--- | + | H
|
||||
# | | |
|
||||
# | | |
|
||||
# | o o o | | -- cover
|
||||
# --------------------- -- --
|
||||
# |-------- B --------|
|
||||
#
|
||||
# RC section:
|
||||
set coverY [expr $HCol/2.0]; # The distance from the section z-axis to the edge of the cover concrete -- outer edge of cover concrete
|
||||
set coverZ [expr $BCol/2.0]; # The distance from the section y-axis to the edge of the cover concrete -- outer edge of cover concrete
|
||||
set coreY [expr $coverY-$coverCol]
|
||||
set coreZ [expr $coverZ-$coverCol]
|
||||
set nfY 16; # number of fibers for concrete in y-direction
|
||||
set nfZ 4; # number of fibers for concrete in z-direction
|
||||
section fiberSec $ColSecTag {; # Define the fiber section
|
||||
patch quadr $IDconcU $nfZ $nfY -$coverY $coverZ -$coverY -$coverZ $coverY -$coverZ $coverY $coverZ; # Define the concrete patch
|
||||
layer straight $IDreinf $numBarsCol $barAreaCol -$coreY $coreZ -$coreY -$coreZ; # top layer reinfocement
|
||||
layer straight $IDreinf $numBarsCol $barAreaCol $coreY $coreZ $coreY -$coreZ; # bottom layer reinforcement
|
||||
}; # end of fibersection definition
|
||||
|
||||
# BEAM section:
|
||||
section Elastic $BeamSecTag $Ec $ABeam $IzBeam; # elastic beam section
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
set BeamTransfTag 2; # associate a tag to beam transformation (good practice to keep col and beam separate)
|
||||
set ColTransfType Linear ; # options, Linear PDelta Corotational
|
||||
geomTransf $ColTransfType $ColTransfTag ; # only columns can have PDelta effects (gravity effects)
|
||||
geomTransf Linear $BeamTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
set numIntgrPts 5; # number of integration points for force-based element
|
||||
element nonlinearBeamColumn 1 1 3 $numIntgrPts $ColSecTag $ColTransfTag; # self-explanatory when using variables
|
||||
element nonlinearBeamColumn 2 2 4 $numIntgrPts $ColSecTag $ColTransfTag;
|
||||
element nonlinearBeamColumn 3 3 4 $numIntgrPts $BeamSecTag $BeamTransfTag;
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file $dataDir/DFree.out -time -node 3 4 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file $dataDir/DBase.out -time -node 1 2 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file $dataDir/RBase.out -time -node 1 2 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file $dataDir/Drift.out -time -iNode 1 2 -jNode 3 4 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file $dataDir/FCol.out -time -ele 1 2 globalForce; # element forces -- column
|
||||
recorder Element -file $dataDir/FBeam.out -time -ele 3 globalForce; # element forces -- beam
|
||||
recorder Element -file $dataDir/ForceColSec1.out -time -ele 1 2 section 1 force; # Column section forces, axial and moment, node i
|
||||
recorder Element -file $dataDir/DefoColSec1.out -time -ele 1 2 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file $dataDir/ForceColSec$numIntgrPts.out -time -ele 1 2 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file $dataDir/DefoColSec$numIntgrPts.out -time -ele 1 2 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
recorder Element -file $dataDir/ForceBeamSec1.out -time -ele 3 section 1 force; # Beam section forces, axial and moment, node i
|
||||
recorder Element -file $dataDir/DefoBeamSec1.out -time -ele 3 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file $dataDir/ForceBeamSec$numIntgrPts.out -time -ele 3 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file $dataDir/DefoBeamSec$numIntgrPts.out -time -ele 3 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
set WzBeam [expr $Weight/$LBeam];
|
||||
pattern Plain 1 Linear {
|
||||
eleLoad -ele 3 -type -beamUniform -$WzBeam ; # distributed superstructure-weight on beam
|
||||
}
|
||||
# Gravity-analysis parameters -- load-controlled static analysis
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
139
examples/data/Ex4.Portal2D.build.InelasticSection.tcl.txt
Normal file
139
examples/data/Ex4.Portal2D.build.InelasticSection.tcl.txt
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# --------------------------------------------------------------------------------------------------
|
||||
# Example4. 2D Portal Frame-- Build Model
|
||||
# nonlinearBeamColumn element, uniaxial inelastic section
|
||||
# Silvia Mazzoni & Frank McKenna, 2006
|
||||
#
|
||||
# ^Y
|
||||
# |
|
||||
# 3_________(3)________4 __
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# (1) (2) LCol
|
||||
# | | |
|
||||
# | | |
|
||||
# | | |
|
||||
# =1= =2= _|_ -------->X
|
||||
# |----------LBeam------------|
|
||||
#
|
||||
|
||||
# SET UP ----------------------------------------------------------------------------
|
||||
wipe; # clear memory of all past model definitions
|
||||
model BasicBuilder -ndm 2 -ndf 3; # Define the model builder, ndm=#dimension, ndf=#dofs
|
||||
set dataDir Data; # set up name of data directory
|
||||
file mkdir $dataDir; # create data directory
|
||||
set GMdir "GMfiles"; # ground-motion file directory
|
||||
source LibUnits.tcl; # define basic and system units
|
||||
|
||||
# define GEOMETRY -------------------------------------------------------------
|
||||
set LCol [expr 36*$ft]; # column length
|
||||
set LBeam [expr 42*$ft]; # beam length
|
||||
set Weight [expr 4000.*$kip]; # superstructure weight
|
||||
# define section geometry
|
||||
set HCol [expr 5.*$ft]; # Column Depth
|
||||
set BCol [expr 4.*$ft]; # Column Width
|
||||
set HBeam [expr 8.*$ft]; # Beam Depth
|
||||
set BBeam [expr 5.*$ft]; # Beam Width
|
||||
|
||||
# calculated parameters
|
||||
set PCol [expr $Weight/2]; # nodal dead-load weight per column
|
||||
set Mass [expr $PCol/$g]; # nodal mass
|
||||
set MCol [expr 1./12.*($Weight/$LBeam)*pow($LBeam,2)]; # beam-end moment due to distributed load.
|
||||
# calculated geometry parameters
|
||||
set ACol [expr $BCol*$HCol]; # cross-sectional area
|
||||
set ABeam [expr $BBeam*$HBeam];
|
||||
set IzCol [expr 1./12.*$BCol*pow($HCol,3)]; # Column moment of inertia
|
||||
set IzBeam [expr 1./12.*$BBeam*pow($HBeam,3)]; # Beam moment of inertia
|
||||
|
||||
# nodal coordinates:
|
||||
node 1 0 0; # node#, X, Y
|
||||
node 2 $LBeam 0
|
||||
node 3 0 $LCol
|
||||
node 4 $LBeam $LCol
|
||||
|
||||
# Single point constraints -- Boundary Conditions
|
||||
fix 1 1 1 0; # node DX DY RZ
|
||||
fix 2 1 1 0; # node DX DY RZ
|
||||
fix 3 0 0 0
|
||||
fix 4 0 0 0
|
||||
|
||||
# nodal masses:
|
||||
mass 3 $Mass 0. 0.; # node#, Mx My Mz, Mass=Weight/g, neglect rotational inertia at nodes
|
||||
mass 4 $Mass 0. 0.
|
||||
|
||||
# Define ELEMENTS & SECTIONS -------------------------------------------------------------
|
||||
set ColMatTagFlex 2; # assign a tag number to the column flexural behavior
|
||||
set ColMatTagAxial 3; # assign a tag number to the column axial behavior
|
||||
set ColSecTag 1; # assign a tag number to the column section tag
|
||||
set BeamSecTag 2; # assign a tag number to the beam section tag
|
||||
|
||||
# MATERIAL parameters
|
||||
set fc [expr -4*$ksi]; # CONCRETE Compressive Strength (+Tension, -Compression)
|
||||
set Ec [expr 57*$ksi*sqrt(-$fc/$psi)]; # Concrete Elastic Modulus
|
||||
|
||||
# COLUMN section
|
||||
# calculated stiffness parameters
|
||||
set EICol [expr $Ec*$IzCol]; # EI, for moment-curvature relationship
|
||||
set EACol [expr $Ec*$ACol]; # EA, for axial-force-strain relationship
|
||||
set MyCol [expr 130000*$kip*$in]; # yield moment
|
||||
set PhiYCol [expr 0.65e-4/$in]; # yield curvature
|
||||
set EIColCrack [expr $MyCol/$PhiYCol]; # cracked section inertia
|
||||
set b 0.01 ; # strain-hardening ratio (ratio between post-yield tangent and initial elastic tangent)
|
||||
uniaxialMaterial Steel01 $ColMatTagFlex $MyCol $EIColCrack $b; # bilinear behavior for flexure
|
||||
uniaxialMaterial Elastic $ColMatTagAxial $EACol; # this is not used as a material, this is an axial-force-strain response
|
||||
section Aggregator $ColSecTag $ColMatTagAxial P $ColMatTagFlex Mz; # combine axial and flexural behavior into one section (no P-M interaction here)
|
||||
|
||||
# BEAM section:
|
||||
section Elastic $BeamSecTag $Ec $ABeam $IzBeam; # elastic beam section
|
||||
|
||||
# define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system
|
||||
set ColTransfTag 1; # associate a tag to column transformation
|
||||
set BeamTransfTag 2; # associate a tag to beam transformation (good practice to keep col and beam separate)
|
||||
set ColTransfType Linear ; # options, Linear PDelta Corotational
|
||||
geomTransf $ColTransfType $ColTransfTag ; # only columns can have PDelta effects (gravity effects)
|
||||
geomTransf Linear $BeamTransfTag ;
|
||||
|
||||
# element connectivity:
|
||||
set numIntgrPts 5; # number of integration points for force-based element
|
||||
element nonlinearBeamColumn 1 1 3 $numIntgrPts $ColSecTag $ColTransfTag; # self-explanatory when using variables
|
||||
element nonlinearBeamColumn 2 2 4 $numIntgrPts $ColSecTag $ColTransfTag;
|
||||
element nonlinearBeamColumn 3 3 4 $numIntgrPts $BeamSecTag $BeamTransfTag;
|
||||
|
||||
# Define RECORDERS -------------------------------------------------------------
|
||||
recorder Node -file $dataDir/DFree.out -time -node 3 4 -dof 1 2 3 disp; # displacements of free nodes
|
||||
recorder Node -file $dataDir/DBase.out -time -node 1 2 -dof 1 2 3 disp; # displacements of support nodes
|
||||
recorder Node -file $dataDir/RBase.out -time -node 1 2 -dof 1 2 3 reaction; # support reaction
|
||||
recorder Drift -file $dataDir/Drift.out -time -iNode 1 2 -jNode 3 4 -dof 1 -perpDirn 2 ; # lateral drift
|
||||
recorder Element -file $dataDir/FCol.out -time -ele 1 2 globalForce; # element forces -- column
|
||||
recorder Element -file $dataDir/FBeam.out -time -ele 3 globalForce; # element forces -- beam
|
||||
recorder Element -file $dataDir/ForceColSec1.out -time -ele 1 2 section 1 force; # Column section forces, axial and moment, node i
|
||||
recorder Element -file $dataDir/DefoColSec1.out -time -ele 1 2 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file $dataDir/ForceColSec$numIntgrPts.out -time -ele 1 2 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file $dataDir/DefoColSec$numIntgrPts.out -time -ele 1 2 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
recorder Element -file $dataDir/ForceBeamSec1.out -time -ele 3 section 1 force; # Beam section forces, axial and moment, node i
|
||||
recorder Element -file $dataDir/DefoBeamSec1.out -time -ele 3 section 1 deformation; # section deformations, axial and curvature, node i
|
||||
recorder Element -file $dataDir/ForceBeamSec$numIntgrPts.out -time -ele 3 section $numIntgrPts force; # section forces, axial and moment, node j
|
||||
recorder Element -file $dataDir/DefoBeamSec$numIntgrPts.out -time -ele 3 section $numIntgrPts deformation; # section deformations, axial and curvature, node j
|
||||
|
||||
# define GRAVITY -------------------------------------------------------------
|
||||
set WzBeam [expr $Weight/$LBeam];
|
||||
pattern Plain 1 Linear {
|
||||
eleLoad -ele 3 -type -beamUniform -$WzBeam ; # distributed superstructure-weight on beam
|
||||
}
|
||||
# Gravity-analysis parameters -- load-controlled static analysis
|
||||
set Tol 1.0e-8; # convergence tolerance for test
|
||||
constraints Plain; # how it handles boundary conditions
|
||||
numberer Plain; # renumber dof's to minimize band-width (optimization), if you want to
|
||||
system BandGeneral; # how to store and solve the system of equations in the analysis
|
||||
test NormDispIncr $Tol 6 ; # determine if convergence has been achieved at the end of an iteration step
|
||||
algorithm Newton; # use Newton's solution algorithm: updates tangent stiffness at every iteration
|
||||
set NstepGravity 10; # apply gravity in 10 steps
|
||||
set DGravity [expr 1./$NstepGravity]; # first load increment;
|
||||
integrator LoadControl $DGravity; # determine the next time step for an analysis
|
||||
analysis Static; # define type of analysis static or transient
|
||||
analyze $NstepGravity; # apply gravity
|
||||
|
||||
# ------------------------------------------------- maintain constant gravity loads and reset time to zero
|
||||
loadConst -time 0.0
|
||||
|
||||
puts "Model Built"
|
||||
302
examples/eigen_two_storey_one_bay_frame.osmodel
Normal file
302
examples/eigen_two_storey_one_bay_frame.osmodel
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Eigen - Two-Storey One-Bay Frame",
|
||||
"description": "Two-storey one-bay elastic frame with two-mode eigenvalue analysis.",
|
||||
"author": "OpenSees Wiki / Chopra Example 10.5",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "N1",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "N2",
|
||||
"coords": [
|
||||
240.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "N3",
|
||||
"coords": [
|
||||
0.0,
|
||||
120.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.25906735751295334,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "N4",
|
||||
"coords": [
|
||||
240.0,
|
||||
120.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.25906735751295334,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "N5",
|
||||
"coords": [
|
||||
0.0,
|
||||
240.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.12953367875647667,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "N6",
|
||||
"coords": [
|
||||
240.0,
|
||||
240.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.12953367875647667,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Column-L1",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 63.41,
|
||||
"Iz": 640.0,
|
||||
"Iy": null,
|
||||
"G": null,
|
||||
"J": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Frame-L2",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 63.41,
|
||||
"Iz": 320.0,
|
||||
"Iy": null,
|
||||
"G": null,
|
||||
"J": null
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "C1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "C2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "C3",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "C4",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
4,
|
||||
6
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "B1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "B2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
5,
|
||||
6
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"mp_constraints": [],
|
||||
"time_series": [],
|
||||
"load_patterns": [],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Modal-2",
|
||||
"type": "Modal",
|
||||
"n_modes": 2,
|
||||
"solver": "genBandArpack"
|
||||
}
|
||||
]
|
||||
}
|
||||
106
examples/eigen_two_storey_one_bay_frame.py
Normal file
106
examples/eigen_two_storey_one_bay_frame.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
"""Eigen analysis of a two-storey one-bay frame.
|
||||
|
||||
OpenSees Wiki tutorial:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=Eigen_analysis_of_a_two-storey_one-bay_frame
|
||||
|
||||
Two-storey one-bay elastic frame from Chopra Example 10.5:
|
||||
- 2D frame, ndm=2 / ndf=3
|
||||
- elastic columns + elastic beams
|
||||
- lumped masses only in Ux
|
||||
- modal analysis for the first two modes
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/eigen_two_storey_one_bay_frame.py
|
||||
|
||||
Produces ``examples/eigen_two_storey_one_bay_frame.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
ModalCase,
|
||||
Node,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
|
||||
|
||||
M = 100.0 / 386.0
|
||||
NUM_MODES = 2
|
||||
|
||||
A = 63.41
|
||||
I = 320.0
|
||||
E = 29000.0
|
||||
L = 240.0
|
||||
H = 120.0
|
||||
|
||||
REFERENCE_TCL = Path(__file__).resolve().parent / "data" / "EigenAnal_twoStoreyFrame1.tcl.txt"
|
||||
|
||||
|
||||
def build_eigen_two_storey_one_bay_frame() -> Project:
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Eigen - Two-Storey One-Bay Frame",
|
||||
author="OpenSees Wiki / Chopra Example 10.5",
|
||||
description=(
|
||||
"Two-storey one-bay elastic frame with two-mode eigenvalue analysis."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(id=1, name="N1", coords=(0.0, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="N2", coords=(L, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=3, name="N3", coords=(0.0, H, 0.0), mass=(M, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=4, name="N4", coords=(L, H, 0.0), mass=(M, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=5, name="N5", coords=(0.0, 2.0 * H, 0.0), mass=(M / 2.0, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=6, name="N6", coords=(L, 2.0 * H, 0.0), mass=(M / 2.0, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(id=1, name="Column-L1", E=E, A=A, Iz=2.0 * I),
|
||||
ElasticSection(id=2, name="Frame-L2", E=E, A=A, Iz=I),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(id=1, name="C1", nodes=(1, 3), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=2, name="C2", nodes=(3, 5), section_id=2, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=3, name="C3", nodes=(2, 4), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=4, name="C4", nodes=(4, 6), section_id=2, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=5, name="B1", nodes=(3, 4), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=6, name="B2", nodes=(5, 6), section_id=2, geom_transf="Linear"),
|
||||
],
|
||||
analyses=[
|
||||
ModalCase(id=1, name="Modal-2", n_modes=NUM_MODES),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_eigen_two_storey_one_bay_frame()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Reference Tcl: {REFERENCE_TCL.name}")
|
||||
print(f" Nodes: {len(project.nodes)}, elements: {len(project.elements)}")
|
||||
print(f" Modes: {NUM_MODES}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
330
examples/eigen_two_storey_shear_frame.osmodel
Normal file
330
examples/eigen_two_storey_shear_frame.osmodel
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Eigen - Two-Storey Shear Frame",
|
||||
"description": "Two-storey shear frame with equalDOF floor constraints and two-mode eigenvalue analysis.",
|
||||
"author": "OpenSees Wiki / Chopra Example 10.4",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "N1",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "N2",
|
||||
"coords": [
|
||||
288.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "N3",
|
||||
"coords": [
|
||||
0.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.25906735751295334,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "N4",
|
||||
"coords": [
|
||||
288.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.25906735751295334,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "N5",
|
||||
"coords": [
|
||||
0.0,
|
||||
288.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.12953367875647667,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "N6",
|
||||
"coords": [
|
||||
288.0,
|
||||
288.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.12953367875647667,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Column-L1",
|
||||
"type": "ElasticSection",
|
||||
"E": 30000.0,
|
||||
"A": 63.41,
|
||||
"Iz": 640.0,
|
||||
"Iy": null,
|
||||
"G": null,
|
||||
"J": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Column-L2",
|
||||
"type": "ElasticSection",
|
||||
"E": 30000.0,
|
||||
"A": 63.41,
|
||||
"Iz": 320.0,
|
||||
"Iy": null,
|
||||
"G": null,
|
||||
"J": null
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Beam-Rigid",
|
||||
"type": "ElasticSection",
|
||||
"E": 30000.0,
|
||||
"A": 63.41,
|
||||
"Iz": 10000000000000.0,
|
||||
"Iy": null,
|
||||
"G": null,
|
||||
"J": null
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "C1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "C2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "C3",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "C4",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
4,
|
||||
6
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "B1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 3,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "B2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
5,
|
||||
6
|
||||
],
|
||||
"section_id": 3,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"mp_constraints": [
|
||||
{
|
||||
"retained_node": 3,
|
||||
"constrained_node": 4,
|
||||
"dofs": [
|
||||
2,
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"retained_node": 5,
|
||||
"constrained_node": 6,
|
||||
"dofs": [
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"time_series": [],
|
||||
"load_patterns": [],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Modal-2",
|
||||
"type": "Modal",
|
||||
"n_modes": 2,
|
||||
"solver": "genBandArpack"
|
||||
}
|
||||
]
|
||||
}
|
||||
117
examples/eigen_two_storey_shear_frame.py
Normal file
117
examples/eigen_two_storey_shear_frame.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
"""Eigen analysis of a two-storey shear frame.
|
||||
|
||||
OpenSees Wiki tutorial:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=Eigen_analysis_of_a_two-story_shear_frame
|
||||
|
||||
Idealized two-storey shear frame from Chopra Example 10.4:
|
||||
- 2D frame, ndm=2 / ndf=3
|
||||
- beams modeled as flexurally rigid (very large Iz)
|
||||
- floor nodes tied with equalDOF in Uy and Rz
|
||||
- lumped masses only in Ux
|
||||
- modal analysis for the first two modes
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/eigen_two_storey_shear_frame.py
|
||||
|
||||
Produces ``examples/eigen_two_storey_shear_frame.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
EqualDOFConstraint,
|
||||
ModalCase,
|
||||
Node,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
|
||||
|
||||
M = 100.0 / 386.0
|
||||
NUM_MODES = 2
|
||||
|
||||
AC = 63.41
|
||||
IC = 320.0
|
||||
E = 30000.0
|
||||
IB = 10e12
|
||||
AB = 63.41
|
||||
|
||||
L = 288.0
|
||||
H = 144.0
|
||||
|
||||
REFERENCE_TCL = Path(__file__).resolve().parent / "data" / "EigenAnal_twoStoreyShearFrame7.tcl.txt"
|
||||
|
||||
|
||||
def build_eigen_two_storey_shear_frame() -> Project:
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Eigen - Two-Storey Shear Frame",
|
||||
author="OpenSees Wiki / Chopra Example 10.4",
|
||||
description=(
|
||||
"Two-storey shear frame with equalDOF floor constraints and "
|
||||
"two-mode eigenvalue analysis."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(id=1, name="N1", coords=(0.0, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="N2", coords=(L, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=3, name="N3", coords=(0.0, H, 0.0), mass=(M, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=4, name="N4", coords=(L, H, 0.0), mass=(M, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=5, name="N5", coords=(0.0, 2.0 * H, 0.0), mass=(M / 2.0, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=6, name="N6", coords=(L, 2.0 * H, 0.0), mass=(M / 2.0, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
mp_constraints=[
|
||||
EqualDOFConstraint(retained_node=3, constrained_node=4, dofs=(2, 3)),
|
||||
EqualDOFConstraint(retained_node=5, constrained_node=6, dofs=(2, 3)),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(id=1, name="Column-L1", E=E, A=AC, Iz=2.0 * IC),
|
||||
ElasticSection(id=2, name="Column-L2", E=E, A=AC, Iz=IC),
|
||||
ElasticSection(id=3, name="Beam-Rigid", E=E, A=AB, Iz=IB),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(id=1, name="C1", nodes=(1, 3), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=2, name="C2", nodes=(3, 5), section_id=2, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=3, name="C3", nodes=(2, 4), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=4, name="C4", nodes=(4, 6), section_id=2, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=5, name="B1", nodes=(3, 4), section_id=3, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=6, name="B2", nodes=(5, 6), section_id=3, geom_transf="Linear"),
|
||||
],
|
||||
analyses=[
|
||||
ModalCase(id=1, name="Modal-2", n_modes=NUM_MODES),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_eigen_two_storey_shear_frame()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Reference Tcl: {REFERENCE_TCL.name}")
|
||||
print(f" Nodes: {len(project.nodes)}, elements: {len(project.elements)}")
|
||||
print(f" MP constraints: {len(project.mp_constraints)}, modes: {NUM_MODES}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
993
examples/elastic_frame.osmodel
Normal file
993
examples/elastic_frame.osmodel
Normal file
|
|
@ -0,0 +1,993 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Elastic Frame (OpenSees Ex 4)",
|
||||
"description": "3-story 3-bay 2D elastic frame, AISC W-shape sections, gravity (distributed) + lateral (point) + 5-mode eigen.",
|
||||
"author": "OpenSees Examples Manual",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [
|
||||
{
|
||||
"id": "X1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X2",
|
||||
"ordinate": 360.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X3",
|
||||
"ordinate": 720.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X4",
|
||||
"ordinate": 1080.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"y_grid_lines": [
|
||||
{
|
||||
"id": "Y1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y2",
|
||||
"ordinate": 162.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y3",
|
||||
"ordinate": 324.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y4",
|
||||
"ordinate": 486.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"z_grid_lines": [
|
||||
{
|
||||
"id": "Z1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "N1",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "N2",
|
||||
"coords": [
|
||||
360.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "N3",
|
||||
"coords": [
|
||||
720.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "N4",
|
||||
"coords": [
|
||||
1080.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "N5",
|
||||
"coords": [
|
||||
0.0,
|
||||
162.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "N6",
|
||||
"coords": [
|
||||
360.0,
|
||||
162.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "N7",
|
||||
"coords": [
|
||||
720.0,
|
||||
162.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "N8",
|
||||
"coords": [
|
||||
1080.0,
|
||||
162.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "N9",
|
||||
"coords": [
|
||||
0.0,
|
||||
324.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "N10",
|
||||
"coords": [
|
||||
360.0,
|
||||
324.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "N11",
|
||||
"coords": [
|
||||
720.0,
|
||||
324.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "N12",
|
||||
"coords": [
|
||||
1080.0,
|
||||
324.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.766692546583851,
|
||||
0.766692546583851,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "N13",
|
||||
"coords": [
|
||||
0.0,
|
||||
486.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.6275879917184265,
|
||||
0.6275879917184265,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "N14",
|
||||
"coords": [
|
||||
360.0,
|
||||
486.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.6275879917184265,
|
||||
0.6275879917184265,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "N15",
|
||||
"coords": [
|
||||
720.0,
|
||||
486.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.6275879917184265,
|
||||
0.6275879917184265,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"name": "N16",
|
||||
"coords": [
|
||||
1080.0,
|
||||
486.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.6275879917184265,
|
||||
0.6275879917184265,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "W14X257-ColExt",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 75.6,
|
||||
"Iz": 3400.0,
|
||||
"Iy": 3400.0,
|
||||
"G": 11200.0,
|
||||
"J": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "W14X311-ColInt",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 91.4,
|
||||
"Iz": 4330.0,
|
||||
"Iy": 4330.0,
|
||||
"G": 11200.0,
|
||||
"J": 1.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "W33X118-Beam1",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 34.7,
|
||||
"Iz": 5900.0,
|
||||
"Iy": 5900.0,
|
||||
"G": 11200.0,
|
||||
"J": 1.0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "W30X116-Beam2",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 34.2,
|
||||
"Iz": 4930.0,
|
||||
"Iy": 4930.0,
|
||||
"G": 11200.0,
|
||||
"J": 1.0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "W24X68-Beam3",
|
||||
"type": "ElasticSection",
|
||||
"E": 29000.0,
|
||||
"A": 20.1,
|
||||
"Iz": 1830.0,
|
||||
"Iy": 1830.0,
|
||||
"G": 11200.0,
|
||||
"J": 1.0
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col-S1-C0",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
5
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-S1-C1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
6
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Col-S1-C2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
7
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Col-S1-C3",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
4,
|
||||
8
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Col-S2-C0",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
5,
|
||||
9
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Col-S2-C1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
6,
|
||||
10
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Col-S2-C2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
7,
|
||||
11
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Col-S2-C3",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
8,
|
||||
12
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Col-S3-C0",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
9,
|
||||
13
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Col-S3-C1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
10,
|
||||
14
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Col-S3-C2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
11,
|
||||
15
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "Col-S3-C3",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
12,
|
||||
16
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "PDelta",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "Beam-F1-B0",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
5,
|
||||
6
|
||||
],
|
||||
"section_id": 3,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "Beam-F1-B1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
6,
|
||||
7
|
||||
],
|
||||
"section_id": 3,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "Beam-F1-B2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
7,
|
||||
8
|
||||
],
|
||||
"section_id": 3,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"name": "Beam-F2-B0",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
9,
|
||||
10
|
||||
],
|
||||
"section_id": 4,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "Beam-F2-B1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
10,
|
||||
11
|
||||
],
|
||||
"section_id": 4,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "Beam-F2-B2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
11,
|
||||
12
|
||||
],
|
||||
"section_id": 4,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"name": "Beam-F3-B0",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
13,
|
||||
14
|
||||
],
|
||||
"section_id": 5,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"name": "Beam-F3-B1",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
14,
|
||||
15
|
||||
],
|
||||
"section_id": 5,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"name": "Beam-F3-B2",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
15,
|
||||
16
|
||||
],
|
||||
"section_id": 5,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Constant",
|
||||
"factor": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Lateral",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [],
|
||||
"element_loads": [
|
||||
{
|
||||
"element_id": 13,
|
||||
"wy": -0.8229166666666666,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 14,
|
||||
"wy": -0.8229166666666666,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 15,
|
||||
"wy": -0.8229166666666666,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 16,
|
||||
"wy": -0.8229166666666666,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 17,
|
||||
"wy": -0.8229166666666666,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 18,
|
||||
"wy": -0.8229166666666666,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 19,
|
||||
"wy": -0.6736111111111112,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 20,
|
||||
"wy": -0.6736111111111112,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
},
|
||||
{
|
||||
"element_id": 21,
|
||||
"wy": -0.6736111111111112,
|
||||
"wz": 0.0,
|
||||
"wx": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Lateral",
|
||||
"type": "Plain",
|
||||
"time_series_id": 2,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 5,
|
||||
"forces": [
|
||||
220.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"node_id": 9,
|
||||
"forces": [
|
||||
180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"node_id": 13,
|
||||
"forces": [
|
||||
90.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 1,
|
||||
"load_factor_increment": 1.0,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Transformation",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Linear",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-10,
|
||||
"max_iter": 10
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Gravity+Lateral",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"n_steps": 1,
|
||||
"load_factor_increment": 1.0,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Transformation",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Linear",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-10,
|
||||
"max_iter": 10
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Modal-5",
|
||||
"type": "Modal",
|
||||
"n_modes": 5,
|
||||
"solver": "genBandArpack"
|
||||
}
|
||||
]
|
||||
}
|
||||
313
examples/elastic_frame.py
Normal file
313
examples/elastic_frame.py
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
"""Elastic Frame Example — OpenSees Examples Manual, Example 4.
|
||||
|
||||
3-story 3-bay 2D elastic moment-resisting frame under gravity
|
||||
(distributed beam loads) + a lateral reference pattern (point loads
|
||||
at each floor's leftmost joint) + a 5-mode eigenvalue analysis.
|
||||
|
||||
Matches the Tcl walkthrough at:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=Elastic_Frame_Example
|
||||
|
||||
Model (kip-in-ksi, ndm=2, ndf=3):
|
||||
|
||||
Floor 3 (z = 486") 13 ──beam19── 14 ──beam20── 15 ──beam21── 16
|
||||
│ │ │ │
|
||||
col9 col10 col11 col12
|
||||
│ │ │ │
|
||||
Floor 2 (z = 324") 9 ──beam16── 10 ─beam17── 11 ──beam18── 12
|
||||
│ │ │ │
|
||||
col5 col6 col7 col8
|
||||
│ │ │ │
|
||||
Floor 1 (z = 162") 5 ──beam13── 6 ─beam14── 7 ──beam15── 8
|
||||
│ │ │ │
|
||||
col1 col2 col3 col4
|
||||
│ │ │ │
|
||||
Base (z = 0") 1 2 3 4
|
||||
(fixed) (fixed) (fixed) (fixed)
|
||||
x = 0 360 720 1080
|
||||
|
||||
Sections (AISC W-shapes):
|
||||
- Exterior column (lines 1, 4): W14X257 A=75.6 Iz=3400
|
||||
- Interior column (lines 2, 3): W14X311 A=91.4 Iz=4330
|
||||
- Floor-1 beam: W33X118 A=34.7 Iz=5900
|
||||
- Floor-2 beam: W30X116 A=34.2 Iz=4930
|
||||
- Floor-3 beam: W24X68 A=20.1 Iz=1830
|
||||
- E = 29000 ksi for all.
|
||||
|
||||
Columns use the PDelta geometric transformation to capture P-Δ; beams
|
||||
use Linear. Gravity is a Constant time series with a uniform
|
||||
distributed load per beam (reference tributary intensity Load / 4 /
|
||||
bay — matches the Tcl ``eleLoad -type -beamUniform [expr -Load/(4*bay)]``).
|
||||
The lateral pattern uses a Linear time series with single-node point
|
||||
loads (220 / 180 / 90 kip at floors 1 / 2 / 3 respectively).
|
||||
|
||||
Expected results (verified against the Tcl reference):
|
||||
- Gravity ΣFy at base: ≈ 2505 kip (Σw · Σbeam-length · 3 floors)
|
||||
- Gravity+Lateral ΣFx: ≈ -490 kip
|
||||
- First five periods (s): 1.0256, 0.3498, 0.1919, 0.1562, 0.1307
|
||||
|
||||
GUI walkthrough: File → Open → elastic_frame.osmodel → Analyze →
|
||||
Run → "Gravity + Lateral" → Display → Show Force Diagram / Modal.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
ConstantTimeSeries,
|
||||
CoordinateGridSystem,
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
GridSystem,
|
||||
LinearTimeSeries,
|
||||
ModalCase,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
StaticCase,
|
||||
UniformElementLoad,
|
||||
UnitSystem,
|
||||
make_grid_lines,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
# Frame geometry (inches).
|
||||
BAY = 360.0 # 30 ft — bay width
|
||||
H_STORY = 162.0 # 13.5 ft — story height
|
||||
N_BAYS = 3
|
||||
N_STORIES = 3
|
||||
|
||||
# Material + section (kip, in, ksi).
|
||||
E = 29000.0
|
||||
|
||||
# Column sections — exterior W14X257 vs interior W14X311.
|
||||
A_COL_EXT, IZ_COL_EXT = 75.6, 3400.0
|
||||
A_COL_INT, IZ_COL_INT = 91.4, 4330.0
|
||||
|
||||
# Beam sections — per floor.
|
||||
A_BEAM_F1, IZ_BEAM_F1 = 34.7, 5900.0 # W33X118 (floor 1)
|
||||
A_BEAM_F2, IZ_BEAM_F2 = 34.2, 4930.0 # W30X116 (floor 2)
|
||||
A_BEAM_F3, IZ_BEAM_F3 = 20.1, 1830.0 # W24X68 (floor 3)
|
||||
|
||||
# Gravity loading (total weight per floor, kip).
|
||||
LOAD_F1 = 1185.0
|
||||
LOAD_F2 = 1185.0
|
||||
LOAD_F3 = 970.0
|
||||
|
||||
# Lateral loading (kip, applied at each floor's leftmost joint, +X).
|
||||
P_F1 = 220.0
|
||||
P_F2 = 180.0
|
||||
P_F3 = 90.0
|
||||
|
||||
# Gravity constant.
|
||||
G = 386.4 # in/s²
|
||||
|
||||
# ─── ID layout ─────────────────────────────────────────────────────
|
||||
# Nodes: row-major, starting from (x=0, y=0). 4 columns × 4 rows = 16.
|
||||
# row r (0=base, 1=floor-1, 2=floor-2, 3=floor-3), col c (0..3):
|
||||
# id = 1 + r*4 + c
|
||||
#
|
||||
# Elements:
|
||||
# cols 1..12 : columns (bottom-to-top, left-to-right within each story)
|
||||
# cols 13..21 : beams (bottom-to-top, left-to-right within each floor)
|
||||
#
|
||||
def _node_id(row: int, col: int) -> int:
|
||||
return 1 + row * (N_BAYS + 1) + col
|
||||
|
||||
|
||||
def _col_id(story: int, col: int) -> int:
|
||||
# Story 1..3, col 0..3.
|
||||
return (story - 1) * (N_BAYS + 1) + col + 1
|
||||
|
||||
|
||||
def _beam_id(floor: int, bay: int) -> int:
|
||||
# Floor 1..3, bay 0..(N_BAYS-1).
|
||||
n_cols_total = N_STORIES * (N_BAYS + 1) # 12
|
||||
return n_cols_total + (floor - 1) * N_BAYS + bay + 1
|
||||
|
||||
|
||||
def build_elastic_frame() -> Project:
|
||||
nodes: list[Node] = []
|
||||
m_floor = {
|
||||
1: LOAD_F1 / ((N_BAYS + 1) * G), # mass per node at floor 1
|
||||
2: LOAD_F2 / ((N_BAYS + 1) * G),
|
||||
3: LOAD_F3 / ((N_BAYS + 1) * G),
|
||||
}
|
||||
for r in range(N_STORIES + 1):
|
||||
for c in range(N_BAYS + 1):
|
||||
nid = _node_id(r, c)
|
||||
x = c * BAY
|
||||
y = r * H_STORY
|
||||
if r == 0:
|
||||
# Base nodes: fix tx, ty, rz (the only active DOFs in ndm=2 ndf=3).
|
||||
restraint = (True, True, False, False, False, True)
|
||||
mass = (0.0,) * 6
|
||||
else:
|
||||
# Floor nodes: all 6 slots free. The runner's dof_idx
|
||||
# picks only (tx, ty, rz) = (0, 1, 5) out of this tuple
|
||||
# when emitting 2D. A stray True at index 5 would fix Rz
|
||||
# at every floor node and make the frame act rigid-joint.
|
||||
restraint = (False,) * 6
|
||||
m = m_floor[r]
|
||||
mass = (m, m, 0.0, 0.0, 0.0, 0.0)
|
||||
nodes.append(Node(
|
||||
id=nid, name=f"N{nid}",
|
||||
coords=(x, y, 0.0),
|
||||
restraint=restraint, mass=mass,
|
||||
))
|
||||
|
||||
# Sections: exterior col, interior col, beam-F1, beam-F2, beam-F3.
|
||||
sections = [
|
||||
ElasticSection(id=1, name="W14X257-ColExt",
|
||||
E=E, A=A_COL_EXT, Iz=IZ_COL_EXT,
|
||||
Iy=IZ_COL_EXT, G=11200.0, J=1.0),
|
||||
ElasticSection(id=2, name="W14X311-ColInt",
|
||||
E=E, A=A_COL_INT, Iz=IZ_COL_INT,
|
||||
Iy=IZ_COL_INT, G=11200.0, J=1.0),
|
||||
ElasticSection(id=3, name="W33X118-Beam1",
|
||||
E=E, A=A_BEAM_F1, Iz=IZ_BEAM_F1,
|
||||
Iy=IZ_BEAM_F1, G=11200.0, J=1.0),
|
||||
ElasticSection(id=4, name="W30X116-Beam2",
|
||||
E=E, A=A_BEAM_F2, Iz=IZ_BEAM_F2,
|
||||
Iy=IZ_BEAM_F2, G=11200.0, J=1.0),
|
||||
ElasticSection(id=5, name="W24X68-Beam3",
|
||||
E=E, A=A_BEAM_F3, Iz=IZ_BEAM_F3,
|
||||
Iy=IZ_BEAM_F3, G=11200.0, J=1.0),
|
||||
]
|
||||
|
||||
# Elements — 12 columns (PDelta) + 9 beams (Linear).
|
||||
elements: list[ElasticBeamColumn] = []
|
||||
for s in range(1, N_STORIES + 1):
|
||||
for c in range(N_BAYS + 1):
|
||||
sec_id = 1 if c in (0, N_BAYS) else 2 # exterior vs interior
|
||||
elements.append(ElasticBeamColumn(
|
||||
id=_col_id(s, c), name=f"Col-S{s}-C{c}",
|
||||
nodes=(_node_id(s - 1, c), _node_id(s, c)),
|
||||
section_id=sec_id, geom_transf="PDelta",
|
||||
))
|
||||
beam_sec = {1: 3, 2: 4, 3: 5}
|
||||
for f in range(1, N_STORIES + 1):
|
||||
for b in range(N_BAYS):
|
||||
elements.append(ElasticBeamColumn(
|
||||
id=_beam_id(f, b), name=f"Beam-F{f}-B{b}",
|
||||
nodes=(_node_id(f, b), _node_id(f, b + 1)),
|
||||
section_id=beam_sec[f], geom_transf="Linear",
|
||||
))
|
||||
|
||||
# Gravity distributed load per beam: w = -Load / (4 × bay). The Tcl
|
||||
# reference divides by 4 (number of column lines), not by the number
|
||||
# of bays — so the distributed load represents a *reference* tributary
|
||||
# intensity, not the total floor weight spread over all beams.
|
||||
# Corresponding reference values: w1 = w2 = -0.8229 kip/in, w3 = -0.6736.
|
||||
floor_total = {1: LOAD_F1, 2: LOAD_F2, 3: LOAD_F3}
|
||||
gravity_element_loads = [
|
||||
UniformElementLoad(
|
||||
element_id=_beam_id(f, b),
|
||||
wy=-floor_total[f] / ((N_BAYS + 1) * BAY),
|
||||
)
|
||||
for f in range(1, N_STORIES + 1)
|
||||
for b in range(N_BAYS)
|
||||
]
|
||||
|
||||
# Lateral point loads at each floor's leftmost joint (+X).
|
||||
lateral_nodes = {
|
||||
_node_id(1, 0): P_F1,
|
||||
_node_id(2, 0): P_F2,
|
||||
_node_id(3, 0): P_F3,
|
||||
}
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Elastic Frame (OpenSees Ex 4)",
|
||||
author="OpenSees Examples Manual",
|
||||
description=(
|
||||
"3-story 3-bay 2D elastic frame, AISC W-shape sections, "
|
||||
"gravity (distributed) + lateral (point) + 5-mode eigen."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2, ndf=3,
|
||||
coord_systems=[
|
||||
CoordinateGridSystem(
|
||||
name="Global",
|
||||
grid=GridSystem(
|
||||
x_grid_lines=make_grid_lines(
|
||||
"X", [c * BAY for c in range(N_BAYS + 1)],
|
||||
),
|
||||
y_grid_lines=make_grid_lines(
|
||||
"Y", [r * H_STORY for r in range(N_STORIES + 1)],
|
||||
),
|
||||
z_grid_lines=make_grid_lines("Z", [0.0]),
|
||||
),
|
||||
),
|
||||
],
|
||||
nodes=nodes,
|
||||
sections=sections,
|
||||
elements=elements,
|
||||
time_series=[
|
||||
ConstantTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=2, name="Lateral"),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1, name="Gravity",
|
||||
time_series_id=1,
|
||||
element_loads=gravity_element_loads,
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=2, name="Lateral",
|
||||
time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=nid, forces=(P, 0, 0, 0, 0, 0))
|
||||
for nid, P in lateral_nodes.items()
|
||||
],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
# Gravity alone — ΣFy at base should equal +3340 kip.
|
||||
StaticCase(
|
||||
id=1, name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=1, load_factor_increment=1.0,
|
||||
system="BandGeneral", constraints="Transformation",
|
||||
integrator="LoadControl", algorithm="Linear",
|
||||
test="NormDispIncr", tolerance=1e-10, max_iter=10,
|
||||
),
|
||||
# Gravity + lateral — ΣFx at base should equal -490 kip.
|
||||
StaticCase(
|
||||
id=2, name="Gravity+Lateral",
|
||||
pattern_ids=[1, 2],
|
||||
n_steps=1, load_factor_increment=1.0,
|
||||
system="BandGeneral", constraints="Transformation",
|
||||
integrator="LoadControl", algorithm="Linear",
|
||||
test="NormDispIncr", tolerance=1e-10, max_iter=10,
|
||||
),
|
||||
# Eigen analysis on the lumped-mass model — 5 modes.
|
||||
ModalCase(id=3, name="Modal-5", n_modes=5),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_elastic_frame()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" ndm={project.ndm}, ndf={project.ndf}, "
|
||||
f"units={project.meta.units.value}")
|
||||
print(f" {len(project.nodes)} nodes, {len(project.elements)} elements")
|
||||
print(f" Total gravity load: {LOAD_F1 + LOAD_F2 + LOAD_F3:.0f} kip")
|
||||
print(f" Total lateral load: {P_F1 + P_F2 + P_F3:.0f} kip")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4268
examples/ex1a_canti2d.osmodel
Normal file
4268
examples/ex1a_canti2d.osmodel
Normal file
File diff suppressed because it is too large
Load diff
241
examples/ex1a_canti2d.py
Normal file
241
examples/ex1a_canti2d.py
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
"""OpenSees Example 1a. 2D Elastic Cantilever Column.
|
||||
|
||||
OpenSees Wiki:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=OpenSees_Example_1a._2D_Elastic_Cantilever_Column
|
||||
|
||||
This model keeps the original Example 1a geometry and packages both
|
||||
lateral-load variants into a single OTKO project:
|
||||
|
||||
- Gravity preload in 10 static LoadControl steps
|
||||
- Displacement-controlled static pushover
|
||||
- UniformExcitation ground-motion analysis using ``BM68elc.acc``
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/ex1a_canti2d.py
|
||||
|
||||
Produces ``examples/ex1a_canti2d.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
StaticCase,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
COLUMN_HEIGHT = 432.0
|
||||
TOP_WEIGHT = 2000.0
|
||||
TOP_MASS_X = 5.18
|
||||
TOP_MASS_Y = 1.0e-9
|
||||
|
||||
AREA = 3_600_000_000.0
|
||||
E_MODULUS = 4227.0
|
||||
IZ = 1_080_000.0
|
||||
|
||||
PUSH_STEP = 0.1
|
||||
PUSH_TARGET = 100.0
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.02
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex1a.Canti2D.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex1a.Canti2D.EQ.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex1a_canti2d() -> Project:
|
||||
values = _ground_motion_values()
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 1a - 2D Elastic Cantilever Column",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=(
|
||||
"Original Ex 1a elastic cantilever column with shared gravity "
|
||||
"preload, static pushover, and BM68elc base-excitation cases."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
name="Base",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(
|
||||
id=2,
|
||||
name="Top",
|
||||
coords=(0.0, COLUMN_HEIGHT, 0.0),
|
||||
mass=(TOP_MASS_X, TOP_MASS_Y, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(
|
||||
id=1,
|
||||
name="Column-Elastic",
|
||||
E=E_MODULUS,
|
||||
A=AREA,
|
||||
Iz=IZ,
|
||||
Iy=IZ,
|
||||
G=1.0,
|
||||
J=1.0,
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(
|
||||
id=1,
|
||||
name="Column",
|
||||
nodes=(1, 2),
|
||||
section_id=1,
|
||||
geom_transf="Linear",
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=2, name="Lateral"),
|
||||
PathTimeSeries(
|
||||
id=3,
|
||||
name="BM68elc",
|
||||
dt=GROUND_DT,
|
||||
factor=GROUND_FACTOR,
|
||||
values=values,
|
||||
file_path=str(GROUND_MOTION_FILE.name),
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(
|
||||
node_id=2,
|
||||
forces=(0.0, -TOP_WEIGHT, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=2,
|
||||
name="Pushover-X",
|
||||
time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(
|
||||
node_id=2,
|
||||
forces=(TOP_WEIGHT, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=3,
|
||||
name="GroundMotion-X",
|
||||
direction=1,
|
||||
accel_series_id=3,
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=10,
|
||||
load_factor_increment=0.1,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2,
|
||||
name="Push",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[2],
|
||||
control_node=2,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
TransientCase(
|
||||
id=3,
|
||||
name="Earthquake",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[3],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=ANALYSIS_STEPS,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
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}")
|
||||
print(f" Reference Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
print(f" Record points: {len(gm.values)}, dt = {GROUND_DT}s, factor = {GROUND_FACTOR}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
8207
examples/ex1a_canti2d_eq.osmodel
Normal file
8207
examples/ex1a_canti2d_eq.osmodel
Normal file
File diff suppressed because it is too large
Load diff
212
examples/ex1a_canti2d_eq.py
Normal file
212
examples/ex1a_canti2d_eq.py
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
"""Time History Analysis of a 2D Elastic Cantilever Column.
|
||||
|
||||
OpenSees Wiki tutorial / examples-manual variant:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=Time_History_Analysis_of_a_2D_Elastic_Cantilever_Column
|
||||
|
||||
This example mirrors ``Ex1a.Canti2D.EQ.modif.tcl`` but expresses it in
|
||||
OTKO's declarative project model:
|
||||
|
||||
- 2D frame (ndm=2, ndf=3), kip-in-sec units
|
||||
- One elastic cantilever column, fixed at the base
|
||||
- Gravity preload applied in 10 static LoadControl steps
|
||||
- Loma Prieta horizontal record ``A10000`` imported from a plain-text list
|
||||
- UniformExcitation in DOF 1 (+X)
|
||||
- Newmark average-acceleration transient with 2% mode-1 stiffness damping
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/ex1a_canti2d_eq.py
|
||||
|
||||
Produces ``examples/ex1a_canti2d_eq.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import (
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
StaticCase,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
from otko.services.peer_record import parse_plain_values
|
||||
|
||||
|
||||
G = 386.0
|
||||
COLUMN_HEIGHT = 432.0
|
||||
TOP_WEIGHT = 2000.0
|
||||
TOP_MASS_X = 5.18
|
||||
|
||||
AREA = 3600.0
|
||||
E_MODULUS = 3225.0
|
||||
IZ = 1_080_000.0
|
||||
|
||||
GROUND_DT = 0.005
|
||||
ANALYSIS_DT = 0.01
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "A10000.txt"
|
||||
REFERENCE_TCL = _ROOT / "data" / "Ex1a.Canti2D.EQ.modif.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex1a_canti2d_eq() -> Project:
|
||||
values = _ground_motion_values()
|
||||
n_steps = len(values) // 2
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="2D Elastic Cantilever EQ (OpenSees Ex 1a)",
|
||||
author="OpenSees Wiki / Examples Manual",
|
||||
description=(
|
||||
"Elastic 2D cantilever with gravity preload + horizontal "
|
||||
"UniformExcitation time history from the A10000 record."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
name="Base",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(
|
||||
id=2,
|
||||
name="Top",
|
||||
coords=(0.0, COLUMN_HEIGHT, 0.0),
|
||||
mass=(TOP_MASS_X, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(
|
||||
id=1,
|
||||
name="RC-Elastic",
|
||||
E=E_MODULUS,
|
||||
A=AREA,
|
||||
Iz=IZ,
|
||||
Iy=IZ,
|
||||
G=1.0,
|
||||
J=1.0,
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(
|
||||
id=1,
|
||||
name="Column",
|
||||
nodes=(1, 2),
|
||||
section_id=1,
|
||||
geom_transf="Linear",
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
PathTimeSeries(
|
||||
id=2,
|
||||
name="A10000",
|
||||
dt=GROUND_DT,
|
||||
factor=G,
|
||||
values=values,
|
||||
file_path=str(GROUND_MOTION_FILE.name),
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(
|
||||
node_id=2,
|
||||
forces=(0.0, -TOP_WEIGHT, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=2,
|
||||
name="GroundMotion-X",
|
||||
direction=1,
|
||||
accel_series_id=2,
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=10,
|
||||
load_factor_increment=0.1,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Linear",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-12,
|
||||
max_iter=10,
|
||||
),
|
||||
TransientCase(
|
||||
id=2,
|
||||
name="Earthquake",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[2],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=n_steps,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="Linear",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-12,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
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}")
|
||||
print(f" Points: {len(gm.values)}, dt = {GROUND_DT}s, factor = g = {G}")
|
||||
print(
|
||||
f" Transient: {project.analyses[1].n_steps} steps at "
|
||||
f"{ANALYSIS_DT}s (every second record point)"
|
||||
)
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4360
examples/ex1b_portal2d.osmodel
Normal file
4360
examples/ex1b_portal2d.osmodel
Normal file
File diff suppressed because it is too large
Load diff
228
examples/ex1b_portal2d.py
Normal file
228
examples/ex1b_portal2d.py
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
"""OpenSees Example 1b. Elastic Portal Frame.
|
||||
|
||||
OpenSees Wiki:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=OpenSees_Example_1b._Elastic_Portal_Frame
|
||||
|
||||
This packages the original Example 1b portal frame into one OTKO
|
||||
project with shared gravity preload and both lateral-load cases:
|
||||
|
||||
- static pushover
|
||||
- base-excitation earthquake analysis with ``BM68elc.acc``
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/ex1b_portal2d.py
|
||||
|
||||
Produces ``examples/ex1b_portal2d.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
StaticCase,
|
||||
TransientCase,
|
||||
UniformElementLoad,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
L_BEAM = 504.0
|
||||
L_COL = 432.0
|
||||
TOP_MASS = 5.18
|
||||
|
||||
A_COL = 3_600_000_000.0
|
||||
IZ_COL = 1_080_000.0
|
||||
A_BEAM = 5_760_000_000.0
|
||||
IZ_BEAM = 4_423_680.0
|
||||
E_MODULUS = 4227.0
|
||||
|
||||
GRAVITY_W = -7.94
|
||||
LATERAL_NODE_LOAD = 2000.0
|
||||
|
||||
PUSH_STEP = 0.1
|
||||
PUSH_TARGET = 10.0
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.02
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex1b.Portal2D.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex1b.Portal2D.EQ.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex1b_portal2d() -> Project:
|
||||
values = _ground_motion_values()
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 1b - Elastic Portal Frame",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=(
|
||||
"Original Ex 1b elastic portal frame with shared gravity "
|
||||
"preload, static pushover, and BM68elc earthquake cases."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
name="Base-L",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(
|
||||
id=2,
|
||||
name="Base-R",
|
||||
coords=(L_BEAM, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(id=3, name="Top-L", coords=(0.0, L_COL, 0.0), mass=(TOP_MASS, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=4, name="Top-R", coords=(L_BEAM, L_COL, 0.0), mass=(TOP_MASS, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(id=1, name="Column", E=E_MODULUS, A=A_COL, Iz=IZ_COL, Iy=IZ_COL, G=1.0, J=1.0),
|
||||
ElasticSection(id=2, name="Beam", E=E_MODULUS, A=A_BEAM, Iz=IZ_BEAM, Iy=IZ_BEAM, G=1.0, J=1.0),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(id=1, name="Col-L", nodes=(1, 3), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=2, name="Col-R", nodes=(2, 4), section_id=1, geom_transf="Linear"),
|
||||
ElasticBeamColumn(id=3, name="Beam", nodes=(3, 4), section_id=2, geom_transf="Linear"),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=2, name="Lateral"),
|
||||
PathTimeSeries(
|
||||
id=3,
|
||||
name="BM68elc",
|
||||
dt=GROUND_DT,
|
||||
factor=GROUND_FACTOR,
|
||||
values=values,
|
||||
file_path=str(GROUND_MOTION_FILE.name),
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
element_loads=[UniformElementLoad(element_id=3, wy=GRAVITY_W)],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=2,
|
||||
name="Pushover-X",
|
||||
time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=3, forces=(LATERAL_NODE_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
NodalLoad(node_id=4, forces=(LATERAL_NODE_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=3,
|
||||
name="GroundMotion-X",
|
||||
direction=1,
|
||||
accel_series_id=3,
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=10,
|
||||
load_factor_increment=0.1,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2,
|
||||
name="Push",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[2],
|
||||
control_node=3,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1, 2],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
TransientCase(
|
||||
id=3,
|
||||
name="Earthquake",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[3],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=ANALYSIS_STEPS,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
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}")
|
||||
print(f" Reference Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
print(f" Record points: {len(gm.values)}, dt = {GROUND_DT}s, factor = {GROUND_FACTOR}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4268
examples/ex2a_canti2d_elastic_element.osmodel
Normal file
4268
examples/ex2a_canti2d_elastic_element.osmodel
Normal file
File diff suppressed because it is too large
Load diff
251
examples/ex2a_canti2d_elastic_element.py
Normal file
251
examples/ex2a_canti2d_elastic_element.py
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
"""OpenSees Example 2a. Elastic Cantilever Column with variables.
|
||||
|
||||
OpenSees Wiki:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=OpenSees_Example_2a._Elastic_Cantilever_Column_with_variables
|
||||
|
||||
This example mirrors the Tcl tutorial's teaching goal: the model is
|
||||
defined from a small set of named parameters, then derived quantities
|
||||
such as mass, section area, and stiffness are computed from them.
|
||||
|
||||
The resulting OTKO project contains:
|
||||
|
||||
- gravity preload
|
||||
- static pushover
|
||||
- earthquake base excitation with ``BM68elc.acc``
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/ex2a_canti2d_elastic_element.py
|
||||
|
||||
Produces ``examples/ex2a_canti2d_elastic_element.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
StaticCase,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
# Geometry and loading variables from the Tcl tutorial.
|
||||
L_COL = 432.0
|
||||
WEIGHT = 2000.0
|
||||
H_COL = 60.0
|
||||
B_COL = 60.0
|
||||
G_ACCEL = 386.4
|
||||
FC = -4.0
|
||||
|
||||
# Derived properties.
|
||||
P_COL = WEIGHT
|
||||
MASS = P_COL / G_ACCEL
|
||||
A_COL = B_COL * H_COL * 1000.0
|
||||
IZ_COL = (1.0 / 12.0) * B_COL * H_COL**3
|
||||
E_C = 57.0 * math.sqrt(-FC * 1000.0)
|
||||
|
||||
# Analysis variables.
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
|
||||
PUSH_TARGET = 0.01 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
H_LOAD = WEIGHT
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.01
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex2a.Canti2D.ElasticElement.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex2a.Canti2D.ElasticElement.EQ.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex2a_canti2d_elastic_element() -> Project:
|
||||
values = _ground_motion_values()
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 2a - Elastic Cantilever Column with Variables",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=(
|
||||
"Variable-driven elastic cantilever model with derived mass, "
|
||||
"section, pushover, and earthquake analysis parameters."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
name="Base",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(
|
||||
id=2,
|
||||
name="Top",
|
||||
coords=(0.0, L_COL, 0.0),
|
||||
mass=(MASS, 1.0e-9, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(
|
||||
id=1,
|
||||
name="Elastic-Column",
|
||||
E=E_C,
|
||||
A=A_COL,
|
||||
Iz=IZ_COL,
|
||||
Iy=IZ_COL,
|
||||
G=1.0,
|
||||
J=1.0,
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(
|
||||
id=1,
|
||||
name="Column",
|
||||
nodes=(1, 2),
|
||||
section_id=1,
|
||||
geom_transf="Linear",
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=2, name="Lateral"),
|
||||
PathTimeSeries(
|
||||
id=3,
|
||||
name="BM68elc",
|
||||
dt=GROUND_DT,
|
||||
factor=GROUND_FACTOR,
|
||||
values=values,
|
||||
file_path=str(GROUND_MOTION_FILE.name),
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(0.0, -P_COL, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=200,
|
||||
name="Pushover-X",
|
||||
time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=400,
|
||||
name="GroundMotion-X",
|
||||
direction=1,
|
||||
accel_series_id=3,
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=N_GRAVITY,
|
||||
load_factor_increment=GRAVITY_STEP,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2,
|
||||
name="Push",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[200],
|
||||
control_node=2,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
TransientCase(
|
||||
id=3,
|
||||
name="Earthquake",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[400],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=ANALYSIS_STEPS,
|
||||
system="SparseGeneral",
|
||||
constraints="Transformation",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="ModifiedNewton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
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)}")
|
||||
print(f" Ground motion file: {GROUND_MOTION_FILE.name}")
|
||||
print(f" Reference Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
print(f" Record points: {len(gm.values)}, dt = {GROUND_DT}s, factor = {GROUND_FACTOR}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4296
examples/ex2b_canti2d_inelastic_section.osmodel
Normal file
4296
examples/ex2b_canti2d_inelastic_section.osmodel
Normal file
File diff suppressed because it is too large
Load diff
276
examples/ex2b_canti2d_inelastic_section.py
Normal file
276
examples/ex2b_canti2d_inelastic_section.py
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
"""OpenSees Example 2b. Nonlinear Cantilever Column: Uniaxial Inelastic Section.
|
||||
|
||||
OpenSees Wiki:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=OpenSees_Example_2b._Nonlinear_Cantilever_Column:_Uniaxial_Inelastic_Section
|
||||
|
||||
This is the first nonlinear cantilever example in the OpenSees tutorial
|
||||
sequence. The column uses:
|
||||
|
||||
- uniaxial elastic axial response
|
||||
- uniaxial bilinear flexural response
|
||||
- a SectionAggregator that combines P and Mz into one section
|
||||
- a force-based nonlinear beam-column element
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/ex2b_canti2d_inelastic_section.py
|
||||
|
||||
Produces ``examples/ex2b_canti2d_inelastic_section.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
AggregatorDOF,
|
||||
ElasticUniaxial,
|
||||
ForceBeamColumn,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
SectionAggregator,
|
||||
StaticCase,
|
||||
Steel01,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
# Geometry / mass variables.
|
||||
L_COL = 432.0
|
||||
WEIGHT = 2000.0
|
||||
H_COL = 60.0
|
||||
B_COL = 60.0
|
||||
G_ACCEL = 386.4
|
||||
|
||||
P_COL = WEIGHT
|
||||
MASS = P_COL / G_ACCEL
|
||||
A_COL = B_COL * H_COL * 1000.0
|
||||
IZ_COL = (1.0 / 12.0) * B_COL * H_COL**3
|
||||
|
||||
# Material / section variables.
|
||||
FC = -4.0
|
||||
E_C = 57.0 * math.sqrt(-FC * 1000.0)
|
||||
EI_COL = E_C * IZ_COL
|
||||
EA_COL = E_C * A_COL
|
||||
MY_COL = 130000.0
|
||||
PHI_Y_COL = 0.65e-4
|
||||
EI_COL_CRACK = MY_COL / PHI_Y_COL
|
||||
HARDENING_RATIO = 0.01
|
||||
NUM_INT_PTS = 5
|
||||
|
||||
# Analysis variables.
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
|
||||
PUSH_TARGET = 0.05 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
H_LOAD = WEIGHT
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.01
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex2b.Canti2D.InelasticSection.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex2b.Canti2D.InelasticSection.EQ.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex2b_canti2d_inelastic_section() -> Project:
|
||||
values = _ground_motion_values()
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 2b - Nonlinear Cantilever Column",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=(
|
||||
"Nonlinear cantilever with an aggregated uniaxial section: "
|
||||
"elastic axial P plus bilinear inelastic Mz in one force-based element."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
name="Base",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(
|
||||
id=2,
|
||||
name="Top",
|
||||
coords=(0.0, L_COL, 0.0),
|
||||
mass=(MASS, 1.0e-9, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
materials=[
|
||||
Steel01(
|
||||
id=2,
|
||||
name="Col-Flex",
|
||||
Fy=MY_COL,
|
||||
E0=EI_COL_CRACK,
|
||||
b=HARDENING_RATIO,
|
||||
),
|
||||
ElasticUniaxial(
|
||||
id=3,
|
||||
name="Col-Axial",
|
||||
E=EA_COL,
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
SectionAggregator(
|
||||
id=1,
|
||||
name="Col-Section",
|
||||
pairings=[
|
||||
AggregatorDOF(material_id=3, dof="P"),
|
||||
AggregatorDOF(material_id=2, dof="Mz"),
|
||||
],
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(
|
||||
id=1,
|
||||
name="Column",
|
||||
nodes=(1, 2),
|
||||
section_id=1,
|
||||
integration_points=NUM_INT_PTS,
|
||||
geom_transf="Linear",
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=200, name="Lateral"),
|
||||
PathTimeSeries(
|
||||
id=400,
|
||||
name="BM68elc",
|
||||
dt=GROUND_DT,
|
||||
factor=GROUND_FACTOR,
|
||||
values=values,
|
||||
file_path=str(GROUND_MOTION_FILE.name),
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(0.0, -P_COL, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=200,
|
||||
name="Pushover-X",
|
||||
time_series_id=200,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=400,
|
||||
name="GroundMotion-X",
|
||||
direction=1,
|
||||
accel_series_id=400,
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=N_GRAVITY,
|
||||
load_factor_increment=GRAVITY_STEP,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2,
|
||||
name="Push",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[200],
|
||||
control_node=2,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
TransientCase(
|
||||
id=3,
|
||||
name="Earthquake",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[400],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=ANALYSIS_STEPS,
|
||||
system="SparseGeneral",
|
||||
constraints="Transformation",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="ModifiedNewton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
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}, "
|
||||
f"EIcr={EI_COL_CRACK:.1f}, b={HARDENING_RATIO}"
|
||||
)
|
||||
print(f" Gravity + pushover + earthquake cases: {len(project.analyses)}")
|
||||
print(f" Ground motion file: {GROUND_MOTION_FILE.name}")
|
||||
print(f" Reference Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
print(f" Record points: {len(gm.values)}, dt = {GROUND_DT}s, factor = {GROUND_FACTOR}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4324
examples/ex2c_canti2d_inelastic_fiber_section.osmodel
Normal file
4324
examples/ex2c_canti2d_inelastic_fiber_section.osmodel
Normal file
File diff suppressed because it is too large
Load diff
324
examples/ex2c_canti2d_inelastic_fiber_section.py
Normal file
324
examples/ex2c_canti2d_inelastic_fiber_section.py
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
"""OpenSees Example 2c. Nonlinear Cantilever Column: Inelastic Fiber Section.
|
||||
|
||||
OpenSees Wiki:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=OpenSees_Example_2c._Nonlinear_Cantilever_Column:_Inelastic_Uniaxial_Materials_in_Fiber_Section
|
||||
|
||||
This example replaces the aggregated uniaxial section of Ex2b with a
|
||||
fiber section built from inelastic uniaxial materials. The fiber section
|
||||
couples axial and flexural behavior naturally through the section
|
||||
integration.
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/ex2c_canti2d_inelastic_fiber_section.py
|
||||
|
||||
Produces ``examples/ex2c_canti2d_inelastic_fiber_section.osmodel``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
Concrete02,
|
||||
FiberSection,
|
||||
ForceBeamColumn,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
RectangularPatch,
|
||||
Steel02,
|
||||
StraightLayer,
|
||||
TransientCase,
|
||||
StaticCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
L_COL = 432.0
|
||||
WEIGHT = 2000.0
|
||||
H_COL = 60.0
|
||||
B_COL = 60.0
|
||||
G_ACCEL = 386.4
|
||||
|
||||
P_COL = WEIGHT
|
||||
MASS = P_COL / G_ACCEL
|
||||
A_COL = B_COL * H_COL
|
||||
IZ_COL = (1.0 / 12.0) * B_COL * H_COL**3
|
||||
|
||||
COVER_COL = 5.0
|
||||
NUM_BARS_COL = 5
|
||||
BAR_AREA_COL = 2.25
|
||||
|
||||
FC = -4.0
|
||||
EC = 57.0 * math.sqrt(-FC * 1000.0)
|
||||
FC1U = FC
|
||||
EPS1U = -0.003
|
||||
FC2U = 0.2 * FC1U
|
||||
EPS2U = -0.01
|
||||
LAMBDA = 0.1
|
||||
FTU = -0.14 * FC1U
|
||||
ETS = FTU / 0.002
|
||||
|
||||
FY = 66.8
|
||||
ES = 29000.0
|
||||
BS = 0.01
|
||||
R0 = 18.0
|
||||
CR1 = 0.925
|
||||
CR2 = 0.15
|
||||
|
||||
NUM_INT_PTS = 5
|
||||
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
|
||||
PUSH_TARGET = 0.01 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
H_LOAD = WEIGHT
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.01
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex2c.Canti2D.InelasticFiberSection.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex2c.Canti2D.InelasticFiberSection.EQ.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex2c_canti2d_inelastic_fiber_section() -> Project:
|
||||
values = _ground_motion_values()
|
||||
cover_y = H_COL / 2.0
|
||||
cover_z = B_COL / 2.0
|
||||
core_y = cover_y - COVER_COL
|
||||
core_z = cover_z - COVER_COL
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 2c - Inelastic Fiber-Section Cantilever",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=(
|
||||
"Nonlinear cantilever with a fiber section built from "
|
||||
"Concrete02 and Steel02 uniaxial materials."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
name="Base",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(
|
||||
id=2,
|
||||
name="Top",
|
||||
coords=(0.0, L_COL, 0.0),
|
||||
mass=(MASS, 1.0e-9, 0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
materials=[
|
||||
Concrete02(
|
||||
id=1,
|
||||
name="Cover-Concrete",
|
||||
fpc=FC1U,
|
||||
epsc0=EPS1U,
|
||||
fpcu=FC2U,
|
||||
epsU=EPS2U,
|
||||
lambda_=LAMBDA,
|
||||
ft=FTU,
|
||||
Ets=ETS,
|
||||
),
|
||||
Steel02(
|
||||
id=2,
|
||||
name="Rebar-Steel",
|
||||
Fy=FY,
|
||||
E0=ES,
|
||||
b=BS,
|
||||
R0=R0,
|
||||
cR1=CR1,
|
||||
cR2=CR2,
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
FiberSection(
|
||||
id=1,
|
||||
name="RC-Fiber-Section",
|
||||
patches=[
|
||||
RectangularPatch(
|
||||
material_id=1,
|
||||
n_fib_y=16,
|
||||
n_fib_z=4,
|
||||
y_i=-cover_y,
|
||||
z_i=-cover_z,
|
||||
y_j=cover_y,
|
||||
z_j=cover_z,
|
||||
),
|
||||
],
|
||||
layers=[
|
||||
StraightLayer(
|
||||
material_id=2,
|
||||
n_bars=NUM_BARS_COL,
|
||||
bar_area=BAR_AREA_COL,
|
||||
y_start=-core_y,
|
||||
z_start=core_z,
|
||||
y_end=-core_y,
|
||||
z_end=-core_z,
|
||||
),
|
||||
StraightLayer(
|
||||
material_id=2,
|
||||
n_bars=NUM_BARS_COL,
|
||||
bar_area=BAR_AREA_COL,
|
||||
y_start=core_y,
|
||||
z_start=core_z,
|
||||
y_end=core_y,
|
||||
z_end=-core_z,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(
|
||||
id=1,
|
||||
name="Column",
|
||||
nodes=(1, 2),
|
||||
section_id=1,
|
||||
integration_points=NUM_INT_PTS,
|
||||
geom_transf="Linear",
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=200, name="Lateral"),
|
||||
PathTimeSeries(
|
||||
id=400,
|
||||
name="BM68elc",
|
||||
dt=GROUND_DT,
|
||||
factor=GROUND_FACTOR,
|
||||
values=values,
|
||||
file_path=str(GROUND_MOTION_FILE.name),
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(0.0, -P_COL, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
PlainLoadPattern(
|
||||
id=200,
|
||||
name="Pushover-X",
|
||||
time_series_id=200,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
),
|
||||
UniformExcitationPattern(
|
||||
id=400,
|
||||
name="GroundMotion-X",
|
||||
direction=1,
|
||||
accel_series_id=400,
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(
|
||||
id=1,
|
||||
name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=N_GRAVITY,
|
||||
load_factor_increment=GRAVITY_STEP,
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
integrator="LoadControl",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
PushoverCase(
|
||||
id=2,
|
||||
name="Push",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[200],
|
||||
control_node=2,
|
||||
control_dof=1,
|
||||
target_disp=PUSH_TARGET,
|
||||
step_size=PUSH_STEP,
|
||||
base_nodes=[1],
|
||||
system="BandGeneral",
|
||||
constraints="Plain",
|
||||
algorithm="Newton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=6,
|
||||
),
|
||||
TransientCase(
|
||||
id=3,
|
||||
name="Earthquake",
|
||||
preload_case_ids=[1],
|
||||
pattern_ids=[400],
|
||||
dt=ANALYSIS_DT,
|
||||
n_steps=ANALYSIS_STEPS,
|
||||
system="SparseGeneral",
|
||||
constraints="Transformation",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25),
|
||||
algorithm="ModifiedNewton",
|
||||
test="EnergyIncr",
|
||||
tolerance=1e-8,
|
||||
max_iter=10,
|
||||
rayleigh_mode1_damping=DAMPING_RATIO,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
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}, "
|
||||
f"bars/layer={NUM_BARS_COL}, bar area={BAR_AREA_COL}"
|
||||
)
|
||||
print(f" Gravity + pushover + earthquake cases: {len(project.analyses)}")
|
||||
print(f" Ground motion file: {GROUND_MOTION_FILE.name}")
|
||||
print(f" Reference Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
print(f" Record points: {len(gm.values)}, dt = {GROUND_DT}s, factor = {GROUND_FACTOR}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4268
examples/ex3_canti2d_elastic_element.osmodel
Normal file
4268
examples/ex3_canti2d_elastic_element.osmodel
Normal file
File diff suppressed because it is too large
Load diff
138
examples/ex3_canti2d_elastic_element.py
Normal file
138
examples/ex3_canti2d_elastic_element.py
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
"""OpenSees Example 3. Cantilever Column with units: elastic build.
|
||||
|
||||
This example follows the separated-build/analysis style of the Tcl
|
||||
tutorial. Here we package the elastic build variant together with the
|
||||
shared gravity, pushover, and uniform-earthquake analyses.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
StaticCase,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
INCH = 1.0
|
||||
KIP = 1.0
|
||||
SEC = 1.0
|
||||
FT = 12.0 * INCH
|
||||
KSI = KIP / INCH**2
|
||||
PSI = KSI / 1000.0
|
||||
G_ACCEL = 32.2 * FT / SEC**2
|
||||
|
||||
L_COL = 36.0 * FT
|
||||
WEIGHT = 2000.0 * KIP
|
||||
H_COL = 5.0 * FT
|
||||
B_COL = 5.0 * FT
|
||||
|
||||
P_COL = WEIGHT
|
||||
MASS = P_COL / G_ACCEL
|
||||
A_COL = B_COL * H_COL
|
||||
IZ_COL = (1.0 / 12.0) * B_COL * H_COL**3
|
||||
FC = -4.0 * KSI
|
||||
E_C = 57.0 * KSI * math.sqrt(-FC / PSI)
|
||||
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
PUSH_TARGET = 0.05 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
H_LOAD = WEIGHT
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.01
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_BUILD_TCL = _ROOT / "data" / "Ex3.Canti2D.build.ElasticElement.tcl.txt"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex3.Canti2D.analyze.Static.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex3.Canti2D.analyze.Dynamic.EQ.Uniform.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex3_canti2d_elastic_element() -> Project:
|
||||
values = _ground_motion_values()
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 3 - Cantilever (Elastic Build)",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description=(
|
||||
"Example 3 elastic cantilever build with unit-scaled geometry "
|
||||
"and shared push / uniform-EQ analysis files."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(id=1, name="Base", coords=(0.0, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="Top", coords=(0.0, L_COL, 0.0), mass=(MASS, 1.0e-9, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(id=1, name="Elastic-Column", E=E_C, A=A_COL, Iz=IZ_COL, Iy=IZ_COL, G=1.0, J=1.0),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(id=1, name="Column", nodes=(1, 2), section_id=1, geom_transf="Linear"),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=200, name="Lateral"),
|
||||
PathTimeSeries(id=400, name="BM68elc", dt=GROUND_DT, factor=GROUND_FACTOR, values=values, file_path=str(GROUND_MOTION_FILE.name)),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(id=1, name="Gravity", time_series_id=1, nodal_loads=[NodalLoad(node_id=2, forces=(0.0, -P_COL, 0.0, 0.0, 0.0, 0.0))]),
|
||||
PlainLoadPattern(id=200, name="Pushover-X", time_series_id=200, nodal_loads=[NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0))]),
|
||||
UniformExcitationPattern(id=400, name="GroundMotion-X", direction=1, accel_series_id=400),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(id=1, name="Gravity", pattern_ids=[1], n_steps=N_GRAVITY, load_factor_increment=GRAVITY_STEP, system="BandGeneral", constraints="Plain", integrator="LoadControl", algorithm="Newton", test="NormDispIncr", tolerance=1e-8, max_iter=6),
|
||||
PushoverCase(id=2, name="Push", preload_case_ids=[1], pattern_ids=[200], control_node=2, control_dof=1, target_disp=PUSH_TARGET, step_size=PUSH_STEP, base_nodes=[1], system="BandGeneral", constraints="Plain", algorithm="Newton", test="EnergyIncr", tolerance=1e-8, max_iter=6),
|
||||
TransientCase(id=3, name="Earthquake", preload_case_ids=[1], pattern_ids=[400], dt=ANALYSIS_DT, n_steps=ANALYSIS_STEPS, system="SparseGeneral", constraints="Transformation", integrator="Newmark", integrator_params=(0.5, 0.25), algorithm="ModifiedNewton", test="EnergyIncr", tolerance=1e-8, max_iter=10, rayleigh_mode1_damping=DAMPING_RATIO),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_ex3_canti2d_elastic_element()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Build Tcl: {REFERENCE_BUILD_TCL.name}")
|
||||
print(f" Analysis Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4324
examples/ex3_canti2d_inelastic_fiber_section.osmodel
Normal file
4324
examples/ex3_canti2d_inelastic_fiber_section.osmodel
Normal file
File diff suppressed because it is too large
Load diff
169
examples/ex3_canti2d_inelastic_fiber_section.py
Normal file
169
examples/ex3_canti2d_inelastic_fiber_section.py
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
"""OpenSees Example 3. Cantilever Column with units: fiber-section build."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
Concrete02,
|
||||
FiberSection,
|
||||
ForceBeamColumn,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
RectangularPatch,
|
||||
StaticCase,
|
||||
Steel02,
|
||||
StraightLayer,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
INCH = 1.0
|
||||
KIP = 1.0
|
||||
SEC = 1.0
|
||||
FT = 12.0 * INCH
|
||||
KSI = KIP / INCH**2
|
||||
PSI = KSI / 1000.0
|
||||
IN2 = INCH * INCH
|
||||
G_ACCEL = 32.2 * FT / SEC**2
|
||||
|
||||
L_COL = 36.0 * FT
|
||||
WEIGHT = 2000.0 * KIP
|
||||
H_COL = 5.0 * FT
|
||||
B_COL = 5.0 * FT
|
||||
P_COL = WEIGHT
|
||||
MASS = P_COL / G_ACCEL
|
||||
A_COL = B_COL * H_COL
|
||||
IZ_COL = (1.0 / 12.0) * B_COL * H_COL**3
|
||||
|
||||
COVER_COL = 5.0 * INCH
|
||||
NUM_BARS_COL = 20
|
||||
BAR_AREA_COL = 2.25 * IN2
|
||||
|
||||
FC = -4.0 * KSI
|
||||
EC = 57.0 * KSI * math.sqrt(-FC / PSI)
|
||||
FC1U = FC
|
||||
EPS1U = -0.003
|
||||
FC2U = 0.2 * FC1U
|
||||
EPS2U = -0.01
|
||||
LAMBDA = 0.1
|
||||
FTU = -0.14 * FC1U
|
||||
ETS = FTU / 0.002
|
||||
|
||||
FY = 66.8 * KSI
|
||||
ES = 29000.0 * KSI
|
||||
BS = 0.01
|
||||
R0 = 18.0
|
||||
CR1 = 0.925
|
||||
CR2 = 0.15
|
||||
NUM_INT_PTS = 5
|
||||
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
PUSH_TARGET = 0.05 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
H_LOAD = WEIGHT
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.01
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_BUILD_TCL = _ROOT / "data" / "Ex3.Canti2D.build.InelasticFiberSection.tcl.txt"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex3.Canti2D.analyze.Static.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex3.Canti2D.analyze.Dynamic.EQ.Uniform.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex3_canti2d_inelastic_fiber_section() -> Project:
|
||||
values = _ground_motion_values()
|
||||
cover_y = H_COL / 2.0
|
||||
cover_z = B_COL / 2.0
|
||||
core_y = cover_y - COVER_COL
|
||||
core_z = cover_z - COVER_COL
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 3 - Cantilever (Fiber Section Build)",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description="Example 3 cantilever with inelastic fiber section and shared analysis files.",
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2, ndf=3,
|
||||
nodes=[
|
||||
Node(id=1, name="Base", coords=(0.0, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="Top", coords=(0.0, L_COL, 0.0), mass=(MASS, 1.0e-9, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
Concrete02(id=1, name="Cover-Concrete", fpc=FC1U, epsc0=EPS1U, fpcu=FC2U, epsU=EPS2U, lambda_=LAMBDA, ft=FTU, Ets=ETS),
|
||||
Steel02(id=2, name="Rebar-Steel", Fy=FY, E0=ES, b=BS, R0=R0, cR1=CR1, cR2=CR2),
|
||||
],
|
||||
sections=[
|
||||
FiberSection(
|
||||
id=1,
|
||||
name="RC-Fiber-Section",
|
||||
patches=[RectangularPatch(material_id=1, n_fib_y=16, n_fib_z=4, y_i=-cover_y, z_i=-cover_z, y_j=cover_y, z_j=cover_z)],
|
||||
layers=[
|
||||
StraightLayer(material_id=2, n_bars=NUM_BARS_COL, bar_area=BAR_AREA_COL, y_start=-core_y, z_start=core_z, y_end=-core_y, z_end=-core_z),
|
||||
StraightLayer(material_id=2, n_bars=NUM_BARS_COL, bar_area=BAR_AREA_COL, y_start=core_y, z_start=core_z, y_end=core_y, z_end=-core_z),
|
||||
],
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(id=1, name="Column", nodes=(1, 2), section_id=1, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=200, name="Lateral"),
|
||||
PathTimeSeries(id=400, name="BM68elc", dt=GROUND_DT, factor=GROUND_FACTOR, values=values, file_path=str(GROUND_MOTION_FILE.name)),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(id=1, name="Gravity", time_series_id=1, nodal_loads=[NodalLoad(node_id=2, forces=(0.0, -P_COL, 0.0, 0.0, 0.0, 0.0))]),
|
||||
PlainLoadPattern(id=200, name="Pushover-X", time_series_id=200, nodal_loads=[NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0))]),
|
||||
UniformExcitationPattern(id=400, name="GroundMotion-X", direction=1, accel_series_id=400),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(id=1, name="Gravity", pattern_ids=[1], n_steps=N_GRAVITY, load_factor_increment=GRAVITY_STEP, system="BandGeneral", constraints="Plain", integrator="LoadControl", algorithm="Newton", test="NormDispIncr", tolerance=1e-8, max_iter=6),
|
||||
PushoverCase(id=2, name="Push", preload_case_ids=[1], pattern_ids=[200], control_node=2, control_dof=1, target_disp=PUSH_TARGET, step_size=PUSH_STEP, base_nodes=[1], system="BandGeneral", constraints="Plain", algorithm="Newton", test="EnergyIncr", tolerance=1e-8, max_iter=6),
|
||||
TransientCase(id=3, name="Earthquake", preload_case_ids=[1], pattern_ids=[400], dt=ANALYSIS_DT, n_steps=ANALYSIS_STEPS, system="SparseGeneral", constraints="Transformation", integrator="Newmark", integrator_params=(0.5, 0.25), algorithm="ModifiedNewton", test="EnergyIncr", tolerance=1e-8, max_iter=10, rayleigh_mode1_damping=DAMPING_RATIO),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_ex3_canti2d_inelastic_fiber_section()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Build Tcl: {REFERENCE_BUILD_TCL.name}")
|
||||
print(f" Analysis Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
4296
examples/ex3_canti2d_inelastic_section.osmodel
Normal file
4296
examples/ex3_canti2d_inelastic_section.osmodel
Normal file
File diff suppressed because it is too large
Load diff
142
examples/ex3_canti2d_inelastic_section.py
Normal file
142
examples/ex3_canti2d_inelastic_section.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
"""OpenSees Example 3. Cantilever Column with units: uniaxial inelastic section build."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import math
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
AggregatorDOF,
|
||||
ElasticUniaxial,
|
||||
ForceBeamColumn,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
SectionAggregator,
|
||||
StaticCase,
|
||||
Steel01,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
from otko.services.peer_record import parse_plain_values # noqa: E402
|
||||
|
||||
|
||||
INCH = 1.0
|
||||
KIP = 1.0
|
||||
SEC = 1.0
|
||||
FT = 12.0 * INCH
|
||||
KSI = KIP / INCH**2
|
||||
PSI = KSI / 1000.0
|
||||
G_ACCEL = 32.2 * FT / SEC**2
|
||||
|
||||
L_COL = 36.0 * FT
|
||||
WEIGHT = 2000.0 * KIP
|
||||
H_COL = 5.0 * FT
|
||||
B_COL = 5.0 * FT
|
||||
|
||||
P_COL = WEIGHT
|
||||
MASS = P_COL / G_ACCEL
|
||||
A_COL = B_COL * H_COL
|
||||
IZ_COL = (1.0 / 12.0) * B_COL * H_COL**3
|
||||
FC = -4.0 * KSI
|
||||
E_C = 57.0 * KSI * math.sqrt(-FC / PSI)
|
||||
EA_COL = E_C * A_COL
|
||||
MY_COL = 130000.0 * KIP * INCH
|
||||
PHI_Y_COL = 0.65e-4 / INCH
|
||||
EI_COL_CRACK = MY_COL / PHI_Y_COL
|
||||
HARDENING_RATIO = 0.01
|
||||
NUM_INT_PTS = 5
|
||||
|
||||
N_GRAVITY = 10
|
||||
GRAVITY_STEP = 1.0 / N_GRAVITY
|
||||
PUSH_TARGET = 0.05 * L_COL
|
||||
PUSH_STEP = 0.001 * L_COL
|
||||
H_LOAD = WEIGHT
|
||||
|
||||
GROUND_DT = 0.01
|
||||
GROUND_FACTOR = 1.0
|
||||
ANALYSIS_DT = 0.01
|
||||
ANALYSIS_STEPS = 1000
|
||||
DAMPING_RATIO = 0.02
|
||||
|
||||
_ROOT = Path(__file__).resolve().parent
|
||||
GROUND_MOTION_FILE = _ROOT / "data" / "BM68elc.acc"
|
||||
REFERENCE_BUILD_TCL = _ROOT / "data" / "Ex3.Canti2D.build.InelasticSection.tcl.txt"
|
||||
REFERENCE_PUSH_TCL = _ROOT / "data" / "Ex3.Canti2D.analyze.Static.Push.tcl.txt"
|
||||
REFERENCE_EQ_TCL = _ROOT / "data" / "Ex3.Canti2D.analyze.Dynamic.EQ.Uniform.tcl.txt"
|
||||
|
||||
|
||||
def _ground_motion_values() -> list[float]:
|
||||
return parse_plain_values(GROUND_MOTION_FILE)
|
||||
|
||||
|
||||
def build_ex3_canti2d_inelastic_section() -> Project:
|
||||
values = _ground_motion_values()
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="OpenSees Ex 3 - Cantilever (Inelastic Section Build)",
|
||||
author="OpenSees Wiki / Silvia Mazzoni & Frank McKenna",
|
||||
description="Example 3 cantilever with aggregated uniaxial inelastic section and shared analysis files.",
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2, ndf=3,
|
||||
nodes=[
|
||||
Node(id=1, name="Base", coords=(0.0, 0.0, 0.0), restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="Top", coords=(0.0, L_COL, 0.0), mass=(MASS, 1.0e-9, 0.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
Steel01(id=2, name="Flexural-Steel01", Fy=MY_COL, E0=EI_COL_CRACK, b=HARDENING_RATIO),
|
||||
ElasticUniaxial(id=3, name="Axial-Elastic", E=EA_COL),
|
||||
],
|
||||
sections=[
|
||||
SectionAggregator(id=1, name="Col-Section", pairings=[AggregatorDOF(material_id=3, dof="P"), AggregatorDOF(material_id=2, dof="Mz")]),
|
||||
],
|
||||
elements=[
|
||||
ForceBeamColumn(id=1, name="Column", nodes=(1, 2), section_id=1, integration_points=NUM_INT_PTS, geom_transf="Linear"),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=200, name="Lateral"),
|
||||
PathTimeSeries(id=400, name="BM68elc", dt=GROUND_DT, factor=GROUND_FACTOR, values=values, file_path=str(GROUND_MOTION_FILE.name)),
|
||||
],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(id=1, name="Gravity", time_series_id=1, nodal_loads=[NodalLoad(node_id=2, forces=(0.0, -P_COL, 0.0, 0.0, 0.0, 0.0))]),
|
||||
PlainLoadPattern(id=200, name="Pushover-X", time_series_id=200, nodal_loads=[NodalLoad(node_id=2, forces=(H_LOAD, 0.0, 0.0, 0.0, 0.0, 0.0))]),
|
||||
UniformExcitationPattern(id=400, name="GroundMotion-X", direction=1, accel_series_id=400),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(id=1, name="Gravity", pattern_ids=[1], n_steps=N_GRAVITY, load_factor_increment=GRAVITY_STEP, system="BandGeneral", constraints="Plain", integrator="LoadControl", algorithm="Newton", test="NormDispIncr", tolerance=1e-8, max_iter=6),
|
||||
PushoverCase(id=2, name="Push", preload_case_ids=[1], pattern_ids=[200], control_node=2, control_dof=1, target_disp=PUSH_TARGET, step_size=PUSH_STEP, base_nodes=[1], system="BandGeneral", constraints="Plain", algorithm="Newton", test="EnergyIncr", tolerance=1e-8, max_iter=6),
|
||||
TransientCase(id=3, name="Earthquake", preload_case_ids=[1], pattern_ids=[400], dt=ANALYSIS_DT, n_steps=ANALYSIS_STEPS, system="SparseGeneral", constraints="Transformation", integrator="Newmark", integrator_params=(0.5, 0.25), algorithm="ModifiedNewton", test="EnergyIncr", tolerance=1e-8, max_iter=10, rayleigh_mode1_damping=DAMPING_RATIO),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_ex3_canti2d_inelastic_section()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Build Tcl: {REFERENCE_BUILD_TCL.name}")
|
||||
print(f" Analysis Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_EQ_TCL.name}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1573
examples/ex4_portal2d_elastic_element.osmodel
Normal file
1573
examples/ex4_portal2d_elastic_element.osmodel
Normal file
File diff suppressed because it is too large
Load diff
56
examples/ex4_portal2d_elastic_element.py
Normal file
56
examples/ex4_portal2d_elastic_element.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""OpenSees Example 4. Portal Frame: elastic build."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
|
||||
if __package__:
|
||||
from ._ex4_portal2d_common import ( # noqa: E402
|
||||
ANALYSIS_DT,
|
||||
ANALYSIS_STEPS,
|
||||
ELASTIC_VARIANT,
|
||||
PUSH_STEP,
|
||||
PUSH_TARGET,
|
||||
REFERENCE_PUSH_TCL,
|
||||
REFERENCE_SINE_TCL,
|
||||
build_ex4_portal2d_elastic_element,
|
||||
)
|
||||
else:
|
||||
from _ex4_portal2d_common import ( # noqa: E402
|
||||
ANALYSIS_DT,
|
||||
ANALYSIS_STEPS,
|
||||
ELASTIC_VARIANT,
|
||||
PUSH_STEP,
|
||||
PUSH_TARGET,
|
||||
REFERENCE_PUSH_TCL,
|
||||
REFERENCE_SINE_TCL,
|
||||
build_ex4_portal2d_elastic_element,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_ex4_portal2d_elastic_element()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Build Tcl: {ELASTIC_VARIANT.build_tcl_name}")
|
||||
print(f" Analysis Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_SINE_TCL.name}")
|
||||
print(f" Pushover target = {PUSH_TARGET}, step = {PUSH_STEP}")
|
||||
print(f" Sine transient: dt = {ANALYSIS_DT}s, steps = {ANALYSIS_STEPS}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1633
examples/ex4_portal2d_inelastic_fiber_section.osmodel
Normal file
1633
examples/ex4_portal2d_inelastic_fiber_section.osmodel
Normal file
File diff suppressed because it is too large
Load diff
56
examples/ex4_portal2d_inelastic_fiber_section.py
Normal file
56
examples/ex4_portal2d_inelastic_fiber_section.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""OpenSees Example 4. Portal Frame: fiber-section build."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
|
||||
if __package__:
|
||||
from ._ex4_portal2d_common import ( # noqa: E402
|
||||
ANALYSIS_DT,
|
||||
ANALYSIS_STEPS,
|
||||
FIBER_VARIANT,
|
||||
PUSH_STEP,
|
||||
PUSH_TARGET,
|
||||
REFERENCE_PUSH_TCL,
|
||||
REFERENCE_SINE_TCL,
|
||||
build_ex4_portal2d_inelastic_fiber_section,
|
||||
)
|
||||
else:
|
||||
from _ex4_portal2d_common import ( # noqa: E402
|
||||
ANALYSIS_DT,
|
||||
ANALYSIS_STEPS,
|
||||
FIBER_VARIANT,
|
||||
PUSH_STEP,
|
||||
PUSH_TARGET,
|
||||
REFERENCE_PUSH_TCL,
|
||||
REFERENCE_SINE_TCL,
|
||||
build_ex4_portal2d_inelastic_fiber_section,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_ex4_portal2d_inelastic_fiber_section()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Build Tcl: {FIBER_VARIANT.build_tcl_name}")
|
||||
print(f" Analysis Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_SINE_TCL.name}")
|
||||
print(f" Pushover target = {PUSH_TARGET}, step = {PUSH_STEP}")
|
||||
print(f" Sine transient: dt = {ANALYSIS_DT}s, steps = {ANALYSIS_STEPS}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1605
examples/ex4_portal2d_inelastic_section.osmodel
Normal file
1605
examples/ex4_portal2d_inelastic_section.osmodel
Normal file
File diff suppressed because it is too large
Load diff
56
examples/ex4_portal2d_inelastic_section.py
Normal file
56
examples/ex4_portal2d_inelastic_section.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""OpenSees Example 4. Portal Frame: inelastic uniaxial-section build."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
if __package__ is None or __package__ == "":
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from otko.services import load_project, save_project # noqa: E402
|
||||
|
||||
if __package__:
|
||||
from ._ex4_portal2d_common import ( # noqa: E402
|
||||
ANALYSIS_DT,
|
||||
ANALYSIS_STEPS,
|
||||
INELASTIC_SECTION_VARIANT,
|
||||
PUSH_STEP,
|
||||
PUSH_TARGET,
|
||||
REFERENCE_PUSH_TCL,
|
||||
REFERENCE_SINE_TCL,
|
||||
build_ex4_portal2d_inelastic_section,
|
||||
)
|
||||
else:
|
||||
from _ex4_portal2d_common import ( # noqa: E402
|
||||
ANALYSIS_DT,
|
||||
ANALYSIS_STEPS,
|
||||
INELASTIC_SECTION_VARIANT,
|
||||
PUSH_STEP,
|
||||
PUSH_TARGET,
|
||||
REFERENCE_PUSH_TCL,
|
||||
REFERENCE_SINE_TCL,
|
||||
build_ex4_portal2d_inelastic_section,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_ex4_portal2d_inelastic_section()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Build Tcl: {INELASTIC_SECTION_VARIANT.build_tcl_name}")
|
||||
print(f" Analysis Tcls: {REFERENCE_PUSH_TCL.name}, {REFERENCE_SINE_TCL.name}")
|
||||
print(f" Pushover target = {PUSH_TARGET}, step = {PUSH_STEP}")
|
||||
print(f" Sine transient: dt = {ANALYSIS_DT}s, steps = {ANALYSIS_STEPS}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
335
examples/moment_curvature.osmodel
Normal file
335
examples/moment_curvature.osmodel
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Moment-Curvature (OpenSees Ex 2)",
|
||||
"description": "RC column fibre section — constant axial P + DisplacementControl curvature pushover. Kip-in-ksi units throughout.",
|
||||
"author": "OpenSees Examples Manual",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [
|
||||
{
|
||||
"id": "X1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"y_grid_lines": [
|
||||
{
|
||||
"id": "Y1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"z_grid_lines": [
|
||||
{
|
||||
"id": "Z1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Support",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Crown",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Core-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -6.0,
|
||||
"epsc0": -0.004,
|
||||
"fpcu": -5.0,
|
||||
"epsU": -0.014
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Cover-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -5.0,
|
||||
"epsc0": -0.002,
|
||||
"fpcu": 0.0,
|
||||
"epsU": -0.006
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Steel-60",
|
||||
"type": "Steel01",
|
||||
"Fy": 60.0,
|
||||
"E0": 30000.0,
|
||||
"b": 0.01,
|
||||
"a1": null,
|
||||
"a2": null,
|
||||
"a3": null,
|
||||
"a4": null
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "RC-Column",
|
||||
"type": "FiberSection",
|
||||
"GJ": null,
|
||||
"patches": [
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 1,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": 6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 7.5
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -7.5,
|
||||
"y_j": 12.0,
|
||||
"z_j": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -6.0,
|
||||
"y_j": -10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": 10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 6.0
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": 10.5,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 2,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 0.0,
|
||||
"z_start": 6.0,
|
||||
"y_end": 0.0,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": -10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": -10.5,
|
||||
"z_end": -6.0
|
||||
}
|
||||
],
|
||||
"fibres": []
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "MK-Link",
|
||||
"type": "ZeroLengthSection",
|
||||
"nodes": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"section_id": 1
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "AxialP",
|
||||
"type": "Constant",
|
||||
"factor": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "RefMoment",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "AxialP",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 2,
|
||||
"forces": [
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "RefMoment",
|
||||
"type": "Plain",
|
||||
"time_series_id": 2,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 2,
|
||||
"forces": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "MK",
|
||||
"type": "Pushover",
|
||||
"pattern_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"control_node": 2,
|
||||
"control_dof": 3,
|
||||
"target_disp": 0.0019047619047619052,
|
||||
"step_size": 1.9047619047619053e-05,
|
||||
"base_nodes": [
|
||||
1
|
||||
],
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormUnbalance",
|
||||
"tolerance": 1e-09,
|
||||
"max_iter": 25
|
||||
}
|
||||
]
|
||||
}
|
||||
249
examples/moment_curvature.py
Normal file
249
examples/moment_curvature.py
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
"""Moment-Curvature Example — OpenSees Examples Manual, Example 2.
|
||||
|
||||
Reinforced-concrete column cross-section, fibre discretisation, axial
|
||||
preload + monotonic moment pushover. Mirrors the OpenSees Tcl script
|
||||
at https://opensees.berkeley.edu/wiki/index.php?title=Moment_Curvature_Example
|
||||
|
||||
Model
|
||||
-----
|
||||
Two coincident nodes linked by a ``zeroLengthSection`` carrying the
|
||||
RC fibre section. Node 1 is fully restrained; node 2 is free in Ux
|
||||
(so axial can shorten) and Rz (the curvature DOF). A constant axial
|
||||
load P = -180 kip is applied first via LoadControl(0); then a
|
||||
linear reference moment pattern (Mz = 1 kip·in) is added and
|
||||
DisplacementControl on DOF 3 ramps the curvature to μ·Ky where
|
||||
μ = 15 and Ky is the elastic yield curvature estimate.
|
||||
|
||||
Units: kip, in, ksi (UnitSystem.US_IN_KIP).
|
||||
|
||||
GUI walkthrough: File → Open → moment_curvature.osmodel, Options →
|
||||
Set Display Units → US (in, kip, kip·s²/in, s, ksi), Analyze → Run →
|
||||
MK, Display → Show Pushover Curve.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
Concrete01,
|
||||
ConstantTimeSeries,
|
||||
CoordinateGridSystem,
|
||||
FiberSection,
|
||||
GridSystem,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
RectangularPatch,
|
||||
Steel01,
|
||||
StraightLayer,
|
||||
UnitSystem,
|
||||
ZeroLengthSectionElement,
|
||||
make_grid_lines,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
# Cross-section parameters (kip-in-ksi, from the Tcl example).
|
||||
COL_WIDTH = 15.0 # z-direction dimension
|
||||
COL_DEPTH = 24.0 # y-direction dimension
|
||||
COVER = 1.5
|
||||
AS_BAR = 0.60 # area of one #7 rebar
|
||||
|
||||
FY = 60.0 # steel yield stress, ksi
|
||||
E_STEEL = 30000.0 # steel Young's modulus, ksi
|
||||
HARDENING = 0.01 # strain-hardening ratio
|
||||
|
||||
P_AXIAL = -180.0 # kip, compression
|
||||
MU = 15 # target curvature ductility
|
||||
NUM_INCR = 100 # DisplacementControl increments
|
||||
|
||||
|
||||
def build_moment_curvature() -> Project:
|
||||
"""Build the OpenSees Example 2 Moment-Curvature project."""
|
||||
y1 = COL_DEPTH / 2.0 # 12
|
||||
z1 = COL_WIDTH / 2.0 # 7.5
|
||||
d = COL_DEPTH - COVER # 22.5
|
||||
|
||||
# Yield curvature estimate, assumed elastic + top/bottom steel only.
|
||||
eps_y = FY / E_STEEL # 0.002
|
||||
ky = eps_y / (0.7 * d) # ≈ 1.27e-4
|
||||
max_k = ky * MU # ≈ 1.905e-3
|
||||
d_k = max_k / NUM_INCR # per-step curvature increment
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="Moment-Curvature (OpenSees Ex 2)",
|
||||
author="OpenSees Examples Manual",
|
||||
description=(
|
||||
"RC column fibre section — constant axial P + DisplacementControl "
|
||||
"curvature pushover. Kip-in-ksi units throughout."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2, ndf=3,
|
||||
coord_systems=[
|
||||
# A tiny grid at the section origin so the two coincident
|
||||
# nodes have a visual anchor in the canvas.
|
||||
CoordinateGridSystem(
|
||||
name="Global",
|
||||
grid=GridSystem(
|
||||
x_grid_lines=make_grid_lines("X", [0.0]),
|
||||
y_grid_lines=make_grid_lines("Y", [0.0]),
|
||||
z_grid_lines=make_grid_lines("Z", [0.0]),
|
||||
),
|
||||
),
|
||||
],
|
||||
nodes=[
|
||||
# Node 1 — fully clamped.
|
||||
Node(id=1, name="Support",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True)),
|
||||
# Node 2 — free in Ux and Rz (axial + curvature).
|
||||
Node(id=2, name="Crown",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(False, True, False, False, False, False)),
|
||||
],
|
||||
materials=[
|
||||
# Core concrete — confined (tag 1).
|
||||
Concrete01(id=1, name="Core-Conc",
|
||||
fpc=-6.0, epsc0=-0.004,
|
||||
fpcu=-5.0, epsU=-0.014),
|
||||
# Cover concrete — unconfined (tag 2).
|
||||
Concrete01(id=2, name="Cover-Conc",
|
||||
fpc=-5.0, epsc0=-0.002,
|
||||
fpcu=0.0, epsU=-0.006),
|
||||
# Reinforcing steel — bilinear hardening (tag 3).
|
||||
Steel01(id=3, name="Steel-60",
|
||||
Fy=FY, E0=E_STEEL, b=HARDENING),
|
||||
],
|
||||
sections=[
|
||||
FiberSection(
|
||||
id=1, name="RC-Column",
|
||||
patches=[
|
||||
# Core — confined concrete inside the rebar ring.
|
||||
RectangularPatch(
|
||||
material_id=1, n_fib_y=10, n_fib_z=1,
|
||||
y_i=COVER - y1, z_i=COVER - z1,
|
||||
y_j=y1 - COVER, z_j=z1 - COVER,
|
||||
),
|
||||
# Top cover (unconfined).
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=10, n_fib_z=1,
|
||||
y_i=-y1, z_i=z1 - COVER,
|
||||
y_j=y1, z_j=z1,
|
||||
),
|
||||
# Bottom cover.
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=10, n_fib_z=1,
|
||||
y_i=-y1, z_i=-z1,
|
||||
y_j=y1, z_j=COVER - z1,
|
||||
),
|
||||
# Left cover.
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=2, n_fib_z=1,
|
||||
y_i=-y1, z_i=COVER - z1,
|
||||
y_j=COVER - y1, z_j=z1 - COVER,
|
||||
),
|
||||
# Right cover.
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=2, n_fib_z=1,
|
||||
y_i=y1 - COVER, z_i=COVER - z1,
|
||||
y_j=y1, z_j=z1 - COVER,
|
||||
),
|
||||
],
|
||||
layers=[
|
||||
# Top rebar (3 × #7).
|
||||
StraightLayer(
|
||||
material_id=3, n_bars=3, bar_area=AS_BAR,
|
||||
y_start=y1 - COVER, z_start=z1 - COVER,
|
||||
y_end=y1 - COVER, z_end=COVER - z1,
|
||||
),
|
||||
# Middle rebar (2 × #7).
|
||||
StraightLayer(
|
||||
material_id=3, n_bars=2, bar_area=AS_BAR,
|
||||
y_start=0.0, z_start=z1 - COVER,
|
||||
y_end=0.0, z_end=COVER - z1,
|
||||
),
|
||||
# Bottom rebar (3 × #7).
|
||||
StraightLayer(
|
||||
material_id=3, n_bars=3, bar_area=AS_BAR,
|
||||
y_start=COVER - y1, z_start=z1 - COVER,
|
||||
y_end=COVER - y1, z_end=COVER - z1,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ZeroLengthSectionElement(
|
||||
id=1, name="MK-Link",
|
||||
nodes=(1, 2), section_id=1,
|
||||
),
|
||||
],
|
||||
time_series=[
|
||||
ConstantTimeSeries(id=1, name="AxialP"),
|
||||
LinearTimeSeries(id=2, name="RefMoment"),
|
||||
],
|
||||
load_patterns=[
|
||||
# Constant axial preload at node 2 — Fx = P (compression).
|
||||
PlainLoadPattern(
|
||||
id=1, name="AxialP",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2,
|
||||
forces=(P_AXIAL, 0, 0, 0, 0, 0)),
|
||||
],
|
||||
),
|
||||
# Linear reference moment — Mz = 1.0, DisplacementControl
|
||||
# scales this as it ramps curvature.
|
||||
PlainLoadPattern(
|
||||
id=2, name="RefMoment",
|
||||
time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=2,
|
||||
forces=(0, 0, 0, 0, 0, 1.0)),
|
||||
],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
PushoverCase(
|
||||
id=1, name="MK",
|
||||
pattern_ids=[1, 2],
|
||||
control_node=2, control_dof=3, # Rz = curvature
|
||||
target_disp=max_k,
|
||||
step_size=d_k,
|
||||
base_nodes=[1],
|
||||
test="NormUnbalance",
|
||||
tolerance=1e-9, max_iter=25,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_moment_curvature()
|
||||
project.validate_references()
|
||||
y1 = COL_DEPTH / 2.0
|
||||
eps_y = FY / E_STEEL
|
||||
ky = eps_y / (0.7 * (COL_DEPTH - COVER))
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" ndm={project.ndm}, ndf={project.ndf}, units={project.meta.units.value}")
|
||||
print(f" Estimated yield curvature Ky = {ky:.4e} 1/in")
|
||||
print(f" Target (mu * Ky) = {ky * MU:.4e} 1/in (mu = {MU})")
|
||||
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
516
examples/portal_frame.osmodel
Normal file
516
examples/portal_frame.osmodel
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Portal Frame",
|
||||
"description": "",
|
||||
"author": "Ozan",
|
||||
"units": "SI (m, N, kg, s, Pa)"
|
||||
},
|
||||
"ndm": 3,
|
||||
"ndf": 6,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Base-R",
|
||||
"coords": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Top-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
3.0
|
||||
],
|
||||
"mass": [
|
||||
5000.0,
|
||||
5000.0,
|
||||
5000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Top-R",
|
||||
"coords": [
|
||||
6.0,
|
||||
0.0,
|
||||
3.0
|
||||
],
|
||||
"mass": [
|
||||
5000.0,
|
||||
5000.0,
|
||||
5000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "S420",
|
||||
"type": "Steel01",
|
||||
"Fy": 420000000.0,
|
||||
"E0": 200000000000.0,
|
||||
"b": 0.01,
|
||||
"a1": null,
|
||||
"a2": null,
|
||||
"a3": null,
|
||||
"a4": null
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "W14x90",
|
||||
"type": "ElasticSection",
|
||||
"E": 200000000000.0,
|
||||
"A": 0.017,
|
||||
"Iz": 0.000416,
|
||||
"Iy": 0.000129,
|
||||
"G": 80000000000.0,
|
||||
"J": 2.04e-06
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col-L",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-R",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Beam",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Ramp",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "SineGust",
|
||||
"type": "Path",
|
||||
"factor": 1.0,
|
||||
"dt": 0.01,
|
||||
"times": null,
|
||||
"values": [
|
||||
0.0,
|
||||
0.06279051952931337,
|
||||
0.12533323356430426,
|
||||
0.1873813145857246,
|
||||
0.2486898871648548,
|
||||
0.3090169943749474,
|
||||
0.3681245526846779,
|
||||
0.42577929156507266,
|
||||
0.4817536741017153,
|
||||
0.5358267949789967,
|
||||
0.5877852522924731,
|
||||
0.6374239897486896,
|
||||
0.6845471059286886,
|
||||
0.7289686274214116,
|
||||
0.7705132427757893,
|
||||
0.8090169943749473,
|
||||
0.8443279255020151,
|
||||
0.8763066800438637,
|
||||
0.9048270524660196,
|
||||
0.9297764858882513,
|
||||
0.9510565162951535,
|
||||
0.9685831611286311,
|
||||
0.9822872507286886,
|
||||
0.9921147013144778,
|
||||
0.9980267284282716,
|
||||
1.0,
|
||||
0.9980267284282716,
|
||||
0.9921147013144779,
|
||||
0.9822872507286887,
|
||||
0.9685831611286311,
|
||||
0.9510565162951536,
|
||||
0.9297764858882515,
|
||||
0.9048270524660195,
|
||||
0.8763066800438635,
|
||||
0.844327925502015,
|
||||
0.8090169943749475,
|
||||
0.7705132427757893,
|
||||
0.7289686274214114,
|
||||
0.6845471059286888,
|
||||
0.6374239897486899,
|
||||
0.5877852522924732,
|
||||
0.535826794978997,
|
||||
0.4817536741017152,
|
||||
0.4257792915650729,
|
||||
0.36812455268467814,
|
||||
0.3090169943749475,
|
||||
0.24868988716485524,
|
||||
0.18738131458572457,
|
||||
0.12533323356430454,
|
||||
0.06279051952931358,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"file_path": null
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Lateral",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
50000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "SineGustPattern",
|
||||
"type": "Plain",
|
||||
"time_series_id": 2,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
100000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Linear-Static",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 1,
|
||||
"load_factor_increment": 1.0,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Linear",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-08,
|
||||
"max_iter": 25
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Modal-3",
|
||||
"type": "Modal",
|
||||
"n_modes": 3,
|
||||
"solver": "genBandArpack"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Sine-Gust-2s",
|
||||
"type": "Transient",
|
||||
"pattern_ids": [
|
||||
2
|
||||
],
|
||||
"dt": 0.01,
|
||||
"n_steps": 200,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "Newmark",
|
||||
"integrator_params": [
|
||||
0.5,
|
||||
0.25
|
||||
],
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-06,
|
||||
"max_iter": 25,
|
||||
"rayleigh_alpha_m": 0.0,
|
||||
"rayleigh_beta_k": 0.0
|
||||
}
|
||||
]
|
||||
}
|
||||
138
examples/portal_frame.py
Normal file
138
examples/portal_frame.py
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
"""Build a 3D portal frame with Static + Modal + Transient cases.
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/portal_frame.py
|
||||
|
||||
Produces ``examples/portal_frame.osmodel`` — open it from the GUI's
|
||||
File → Open menu, then exercise:
|
||||
|
||||
- **Static** case → Display → Show Deformed Shape, Show Force Diagram
|
||||
- **Modal** case → Display → Animate Mode Shape
|
||||
- **Transient** case → Display → Time-History Plot, Hysteresis Plot
|
||||
|
||||
The model is a single-bay portal frame loaded laterally:
|
||||
|
||||
Top-L ──── Beam ──── Top-R z
|
||||
│ │ │
|
||||
│ │ │
|
||||
Col-L Col-R └── x
|
||||
│ │
|
||||
Base-L Base-R (y = 0; planar in x-z)
|
||||
|
||||
Mass is lumped at the top nodes so modal/transient solvers have
|
||||
non-singular mass matrices.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
ModalCase,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
StaticCase,
|
||||
Steel01,
|
||||
TransientCase,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
def _sine_pulse_factors() -> list[float]:
|
||||
"""One half-cycle sine over the first 0.5s, then zero for the rest of 2s."""
|
||||
n_pulse = 50 # 0.5 s @ 100 Hz
|
||||
n_total = 200
|
||||
return [math.sin(math.pi * i / n_pulse) if i < n_pulse else 0.0
|
||||
for i in range(n_total)]
|
||||
|
||||
|
||||
def build_portal_frame() -> Project:
|
||||
"""A two-column, one-beam steel portal frame with static + dynamic cases."""
|
||||
return Project(
|
||||
meta=ProjectMeta(name="Portal Frame", author="Ozan", units=UnitSystem.SI_M_N),
|
||||
ndm=3,
|
||||
ndf=6,
|
||||
nodes=[
|
||||
Node(id=1, name="Base-L", coords=(0.0, 0.0, 0.0), restraint=(True,) * 6),
|
||||
Node(id=2, name="Base-R", coords=(6.0, 0.0, 0.0), restraint=(True,) * 6),
|
||||
Node(id=3, name="Top-L", coords=(0.0, 0.0, 3.0),
|
||||
mass=(5000.0, 5000.0, 5000.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=4, name="Top-R", coords=(6.0, 0.0, 3.0),
|
||||
mass=(5000.0, 5000.0, 5000.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
Steel01(id=1, name="S420", Fy=420e6, E0=200e9, b=0.01),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(
|
||||
id=1, name="W14x90",
|
||||
E=200e9, A=0.017,
|
||||
Iz=4.16e-4, Iy=1.29e-4,
|
||||
G=80e9, J=2.04e-6,
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
ElasticBeamColumn(id=1, name="Col-L", nodes=(1, 3), section_id=1),
|
||||
ElasticBeamColumn(id=2, name="Col-R", nodes=(2, 4), section_id=1),
|
||||
ElasticBeamColumn(id=3, name="Beam", nodes=(3, 4), section_id=1),
|
||||
],
|
||||
time_series=[
|
||||
LinearTimeSeries(id=1, name="Ramp"),
|
||||
PathTimeSeries(
|
||||
id=2, name="SineGust",
|
||||
values=_sine_pulse_factors(),
|
||||
dt=0.01,
|
||||
),
|
||||
],
|
||||
load_patterns=[
|
||||
# Pattern 1: 50 kN lateral push at top-left for Static.
|
||||
PlainLoadPattern(
|
||||
id=1, name="Lateral",
|
||||
time_series_id=1,
|
||||
nodal_loads=[NodalLoad(node_id=3, forces=(50_000.0, 0, 0, 0, 0, 0))],
|
||||
),
|
||||
# Pattern 2: 100 kN sine pulse at top-left for Transient.
|
||||
PlainLoadPattern(
|
||||
id=2, name="SineGustPattern",
|
||||
time_series_id=2,
|
||||
nodal_loads=[NodalLoad(node_id=3, forces=(100_000.0, 0, 0, 0, 0, 0))],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
StaticCase(id=1, name="Linear-Static", pattern_ids=[1]),
|
||||
ModalCase(id=2, name="Modal-3", n_modes=3),
|
||||
TransientCase(
|
||||
id=3, name="Sine-Gust-2s",
|
||||
pattern_ids=[2],
|
||||
dt=0.01, n_steps=200, # 2 seconds @ 100 Hz
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_portal_frame()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}' — {len(project.nodes)} nodes, "
|
||||
f"{len(project.elements)} elements, {len(project.analyses)} cases.")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
353
examples/portal_pushover.osmodel
Normal file
353
examples/portal_pushover.osmodel
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "Portal Pushover",
|
||||
"description": "",
|
||||
"author": "Ozan",
|
||||
"units": "SI (m, N, kg, s, Pa)"
|
||||
},
|
||||
"ndm": 3,
|
||||
"ndf": 6,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Base-R",
|
||||
"coords": [
|
||||
6.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Top-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
3.0
|
||||
],
|
||||
"mass": [
|
||||
10000.0,
|
||||
10000.0,
|
||||
10000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Top-R",
|
||||
"coords": [
|
||||
6.0,
|
||||
0.0,
|
||||
3.0
|
||||
],
|
||||
"mass": [
|
||||
10000.0,
|
||||
10000.0,
|
||||
10000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "C30",
|
||||
"type": "Concrete01",
|
||||
"fpc": -30000000.0,
|
||||
"epsc0": -0.002,
|
||||
"fpcu": -0.0,
|
||||
"epsU": -0.005
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "S420",
|
||||
"type": "Steel01",
|
||||
"Fy": 420000000.0,
|
||||
"E0": 200000000000.0,
|
||||
"b": 0.01,
|
||||
"a1": null,
|
||||
"a2": null,
|
||||
"a3": null,
|
||||
"a4": null
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "GJ-spring",
|
||||
"type": "Elastic",
|
||||
"E": 28800000.0,
|
||||
"eta": 0.0,
|
||||
"Eneg": null
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "RC-Column",
|
||||
"type": "FiberSection",
|
||||
"GJ": null,
|
||||
"patches": [
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 1,
|
||||
"n_fib_y": 8,
|
||||
"n_fib_z": 10,
|
||||
"y_i": -0.10999999999999999,
|
||||
"z_i": -0.16,
|
||||
"y_j": 0.10999999999999999,
|
||||
"z_j": 0.16
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 2,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.000314,
|
||||
"y_start": -0.10999999999999999,
|
||||
"z_start": -0.16,
|
||||
"y_end": 0.10999999999999999,
|
||||
"z_end": -0.16
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 2,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.000314,
|
||||
"y_start": -0.10999999999999999,
|
||||
"z_start": 0.16,
|
||||
"y_end": 0.10999999999999999,
|
||||
"z_end": 0.16
|
||||
}
|
||||
],
|
||||
"fibres": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-Agg",
|
||||
"type": "SectionAggregator",
|
||||
"section_id": 1,
|
||||
"pairings": [
|
||||
{
|
||||
"material_id": 3,
|
||||
"dof": "T"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "W14x90",
|
||||
"type": "ElasticSection",
|
||||
"E": 200000000000.0,
|
||||
"A": 0.017,
|
||||
"Iz": 0.000416,
|
||||
"Iy": 0.000129,
|
||||
"G": 80000000000.0,
|
||||
"J": 2.04e-06
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col-L",
|
||||
"type": "BeamWithHinges",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_i_id": 2,
|
||||
"section_j_id": 2,
|
||||
"lp_i": 0.4,
|
||||
"lp_j": 0.01,
|
||||
"E": 200000000000.0,
|
||||
"A": 0.017,
|
||||
"Iz": 0.000416,
|
||||
"Iy": 0.000129,
|
||||
"G": 80000000000.0,
|
||||
"J": 2.04e-06,
|
||||
"geom_transf": "Linear"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-R",
|
||||
"type": "BeamWithHinges",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_i_id": 2,
|
||||
"section_j_id": 2,
|
||||
"lp_i": 0.4,
|
||||
"lp_j": 0.01,
|
||||
"E": 200000000000.0,
|
||||
"A": 0.017,
|
||||
"Iz": 0.000416,
|
||||
"Iy": 0.000129,
|
||||
"G": 80000000000.0,
|
||||
"J": 2.04e-06,
|
||||
"geom_transf": "Linear"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Beam",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 3,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Ramp",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "PushRef",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Push-X",
|
||||
"type": "Pushover",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"control_node": 3,
|
||||
"control_dof": 1,
|
||||
"target_disp": 0.15,
|
||||
"step_size": 0.0005,
|
||||
"base_nodes": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-06,
|
||||
"max_iter": 25
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Modal-3",
|
||||
"type": "Modal",
|
||||
"n_modes": 3,
|
||||
"solver": "genBandArpack"
|
||||
}
|
||||
]
|
||||
}
|
||||
189
examples/portal_pushover.py
Normal file
189
examples/portal_pushover.py
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
"""Portal frame with fiber-section plastic hinges and pushover analysis.
|
||||
|
||||
A single-bay portal frame where the column bases use FiberSections
|
||||
(concrete core + rebar layers) wrapped in a SectionAggregator (for
|
||||
torsion) and assigned to BeamWithHingesElements. The beam and column
|
||||
tops remain elastic.
|
||||
|
||||
Demonstrates the full Phase 9 pipeline:
|
||||
1. Define concrete + steel uniaxialMaterials
|
||||
2. Build a FiberSection with a rectangular concrete patch + rebar layers
|
||||
3. Wrap in a SectionAggregator that adds elastic torsion
|
||||
4. Assign BeamWithHingesElements to the columns (hinges at base only)
|
||||
5. Run a monotonic pushover to 0.15 m lateral displacement
|
||||
6. View the pushover curve and force diagrams
|
||||
|
||||
Run:
|
||||
python examples/portal_pushover.py
|
||||
|
||||
Produces ``examples/portal_pushover.osmodel``.
|
||||
|
||||
GUI walkthrough:
|
||||
File → Open → portal_pushover.osmodel
|
||||
Analyze → Cases → Run "Push-X"
|
||||
Display → Show Pushover Curve → see yielding + hardening
|
||||
Display → Show Force Diagram → M3 at the last pushover step
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
AggregatorDOF,
|
||||
BeamWithHingesElement,
|
||||
Concrete01,
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
ElasticUniaxial,
|
||||
FiberSection,
|
||||
LinearTimeSeries,
|
||||
ModalCase,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
RectangularPatch,
|
||||
SectionAggregator,
|
||||
Steel01,
|
||||
StraightLayer,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
def build_portal_pushover() -> Project:
|
||||
"""Portal frame: 2 columns (hinge at base) + 1 beam (elastic)."""
|
||||
H = 3.0 # story height
|
||||
L = 6.0 # bay width
|
||||
b = 0.30 # column width (y)
|
||||
h = 0.40 # column depth (z)
|
||||
cover = 0.04
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(name="Portal Pushover", author="Ozan",
|
||||
units=UnitSystem.SI_M_N),
|
||||
ndm=3, ndf=6,
|
||||
nodes=[
|
||||
Node(id=1, name="Base-L", coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True,) * 6),
|
||||
Node(id=2, name="Base-R", coords=(L, 0.0, 0.0),
|
||||
restraint=(True,) * 6),
|
||||
Node(id=3, name="Top-L", coords=(0.0, 0.0, H),
|
||||
mass=(10_000.0, 10_000.0, 10_000.0, 0.0, 0.0, 0.0)),
|
||||
Node(id=4, name="Top-R", coords=(L, 0.0, H),
|
||||
mass=(10_000.0, 10_000.0, 10_000.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
# Concrete: unconfined C30 (fpc negative by convention)
|
||||
Concrete01(id=1, name="C30",
|
||||
fpc=-30e6, epsc0=-0.002, fpcu=-0.0, epsU=-0.005),
|
||||
# Steel rebar: S420 bilinear
|
||||
Steel01(id=2, name="S420", Fy=420e6, E0=200e9, b=0.01),
|
||||
# Elastic torsion spring
|
||||
ElasticUniaxial(id=3, name="GJ-spring", E=80e9 * 3.6e-4),
|
||||
],
|
||||
sections=[
|
||||
# FiberSection for the column hinge region:
|
||||
# - Rectangular concrete patch (core, excluding cover for simplicity)
|
||||
# - Bottom rebar layer (3 × Ø20 → A=3×314e-6=942e-6 m²)
|
||||
# - Top rebar layer
|
||||
FiberSection(
|
||||
id=1, name="RC-Column",
|
||||
patches=[RectangularPatch(
|
||||
material_id=1,
|
||||
n_fib_y=8, n_fib_z=10,
|
||||
y_i=-b / 2 + cover, z_i=-h / 2 + cover,
|
||||
y_j=b / 2 - cover, z_j=h / 2 - cover,
|
||||
)],
|
||||
layers=[
|
||||
# Bottom rebar (z = -h/2 + cover)
|
||||
StraightLayer(
|
||||
material_id=2, n_bars=3, bar_area=314e-6,
|
||||
y_start=-b / 2 + cover, z_start=-h / 2 + cover,
|
||||
y_end=b / 2 - cover, z_end=-h / 2 + cover,
|
||||
),
|
||||
# Top rebar (z = +h/2 - cover)
|
||||
StraightLayer(
|
||||
material_id=2, n_bars=3, bar_area=314e-6,
|
||||
y_start=-b / 2 + cover, z_start=h / 2 - cover,
|
||||
y_end=b / 2 - cover, z_end=h / 2 - cover,
|
||||
),
|
||||
],
|
||||
),
|
||||
# Aggregator: FiberSection + elastic torsion
|
||||
SectionAggregator(
|
||||
id=2, name="Col-Agg",
|
||||
section_id=1,
|
||||
pairings=[AggregatorDOF(material_id=3, dof="T")],
|
||||
),
|
||||
# Elastic beam section (for the beam and column elastic interior)
|
||||
ElasticSection(
|
||||
id=3, name="W14x90",
|
||||
E=200e9, A=0.017,
|
||||
Iz=4.16e-4, Iy=1.29e-4,
|
||||
G=80e9, J=2.04e-6,
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
# Columns: BeamWithHinges at the base (hinge at end-i only;
|
||||
# end-j uses the same section but with a tiny Lp so it stays
|
||||
# essentially elastic there).
|
||||
BeamWithHingesElement(
|
||||
id=1, name="Col-L", nodes=(1, 3),
|
||||
section_i_id=2, section_j_id=2,
|
||||
lp_i=0.40, lp_j=0.01, # plastic hinge at base only
|
||||
E=200e9, A=0.017,
|
||||
Iz=4.16e-4, Iy=1.29e-4,
|
||||
G=80e9, J=2.04e-6,
|
||||
),
|
||||
BeamWithHingesElement(
|
||||
id=2, name="Col-R", nodes=(2, 4),
|
||||
section_i_id=2, section_j_id=2,
|
||||
lp_i=0.40, lp_j=0.01,
|
||||
E=200e9, A=0.017,
|
||||
Iz=4.16e-4, Iy=1.29e-4,
|
||||
G=80e9, J=2.04e-6,
|
||||
),
|
||||
# Beam: elastic
|
||||
ElasticBeamColumn(id=3, name="Beam", nodes=(3, 4), section_id=3),
|
||||
],
|
||||
time_series=[LinearTimeSeries(id=1, name="Ramp")],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1, name="PushRef",
|
||||
time_series_id=1,
|
||||
nodal_loads=[NodalLoad(node_id=3, forces=(1.0, 0, 0, 0, 0, 0))],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
PushoverCase(
|
||||
id=1, name="Push-X",
|
||||
pattern_ids=[1],
|
||||
control_node=3, control_dof=1,
|
||||
target_disp=0.15, step_size=0.0005,
|
||||
base_nodes=[1, 2],
|
||||
),
|
||||
ModalCase(id=2, name="Modal-3", n_modes=3),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_portal_pushover()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}' — {len(project.nodes)} nodes, "
|
||||
f"{len(project.elements)} elements, {len(project.analyses)} cases.")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
850
examples/rc_frame_earthquake.osmodel
Normal file
850
examples/rc_frame_earthquake.osmodel
Normal file
|
|
@ -0,0 +1,850 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "RC Frame Earthquake (OpenSees Ex 3.3)",
|
||||
"description": "Ex 3 gravity + uniform base excitation (horizontal, 4-s synthetic record peaking at ~0.35 g) + Rayleigh beta_k",
|
||||
"author": "OpenSees Examples Manual",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [
|
||||
{
|
||||
"id": "X1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X2",
|
||||
"ordinate": 360.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"y_grid_lines": [
|
||||
{
|
||||
"id": "Y1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y2",
|
||||
"ordinate": 144.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"z_grid_lines": [
|
||||
{
|
||||
"id": "Z1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Base-R",
|
||||
"coords": [
|
||||
360.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Top-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.46583850931677023,
|
||||
0.46583850931677023,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Top-R",
|
||||
"coords": [
|
||||
360.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.46583850931677023,
|
||||
0.46583850931677023,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Core-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -6.0,
|
||||
"epsc0": -0.004,
|
||||
"fpcu": -5.0,
|
||||
"epsU": -0.014
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Cover-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -5.0,
|
||||
"epsc0": -0.002,
|
||||
"fpcu": 0.0,
|
||||
"epsU": -0.006
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Steel-60",
|
||||
"type": "Steel01",
|
||||
"Fy": 60.0,
|
||||
"E0": 30000.0,
|
||||
"b": 0.01,
|
||||
"a1": null,
|
||||
"a2": null,
|
||||
"a3": null,
|
||||
"a4": null
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "RC-Col",
|
||||
"type": "FiberSection",
|
||||
"GJ": null,
|
||||
"patches": [
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 1,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": 6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 7.5
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -7.5,
|
||||
"y_j": 12.0,
|
||||
"z_j": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -6.0,
|
||||
"y_j": -10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": 10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 6.0
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": 10.5,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 2,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 0.0,
|
||||
"z_start": 6.0,
|
||||
"y_end": 0.0,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": -10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": -10.5,
|
||||
"z_end": -6.0
|
||||
}
|
||||
],
|
||||
"fibres": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Beam",
|
||||
"type": "ElasticSection",
|
||||
"E": 4030.0,
|
||||
"A": 360.0,
|
||||
"Iz": 8640.0,
|
||||
"Iy": 8640.0,
|
||||
"G": 1500.0,
|
||||
"J": 1.0
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col-L",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-R",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Beam",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Constant",
|
||||
"factor": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "GroundMotion",
|
||||
"type": "Path",
|
||||
"factor": 386.4,
|
||||
"dt": 0.01,
|
||||
"times": null,
|
||||
"values": [
|
||||
0.0,
|
||||
0.0003759997006929128,
|
||||
0.001492139322989129,
|
||||
0.003313120974162101,
|
||||
0.005781044089220584,
|
||||
0.008816778784387096,
|
||||
0.012321847906716393,
|
||||
0.016180778098291576,
|
||||
0.02026387021204836,
|
||||
0.02443033041658253,
|
||||
0.028531695488854605,
|
||||
0.03241547927404673,
|
||||
0.03592896222341777,
|
||||
0.03892304240870259,
|
||||
0.04125606453060492,
|
||||
0.042797543233281915,
|
||||
0.043431698518368936,
|
||||
0.043060724200602765,
|
||||
0.04160771510989262,
|
||||
0.03901918503793526,
|
||||
0.03526711513754839,
|
||||
0.030350481468408082,
|
||||
0.024296220477188758,
|
||||
0.017159602214374983,
|
||||
0.009023992816629927,
|
||||
9.184850993605149e-18,
|
||||
-0.009775992218015735,
|
||||
-0.020143880860353257,
|
||||
-0.03092246242551298,
|
||||
-0.0419125696468492,
|
||||
-0.05290067270632257,
|
||||
-0.06366288085136805,
|
||||
-0.07396927130647578,
|
||||
-0.08358846462469952,
|
||||
-0.09229235935153403,
|
||||
-0.09986093421099113,
|
||||
-0.10608702307869838,
|
||||
-0.11078096685553815,
|
||||
-0.11377504704082295,
|
||||
-0.11492760833525657,
|
||||
-0.11412678195541844,
|
||||
-0.1112937274533204,
|
||||
-0.10638531861325395,
|
||||
-0.09939620831807686,
|
||||
-0.09036021798258695,
|
||||
-0.0793510090594839,
|
||||
-0.06648200702603672,
|
||||
-0.05190556192853958,
|
||||
-0.035811343751739166,
|
||||
-0.018423985333952782,
|
||||
-3.6739403974420595e-17,
|
||||
0.018799985034645625,
|
||||
0.03730348307472823,
|
||||
0.05521868290270173,
|
||||
0.07226305111525734,
|
||||
0.08816778784387104,
|
||||
0.10268206588930338,
|
||||
0.11557698641636838,
|
||||
0.1266491888253022,
|
||||
0.1357240578699029,
|
||||
0.142658477444273,
|
||||
0.14734308760930329,
|
||||
0.14970400926424074,
|
||||
0.14970400926424074,
|
||||
0.14734308760930329,
|
||||
0.14265847744427304,
|
||||
0.13572405786990288,
|
||||
0.12664918882530227,
|
||||
0.11557698641636828,
|
||||
0.10268206588930326,
|
||||
0.088167787843871,
|
||||
0.07226305111525742,
|
||||
0.055218682902701696,
|
||||
0.03730348307472832,
|
||||
0.018799985034645583,
|
||||
5.510910596163089e-17,
|
||||
-0.018799985034645476,
|
||||
-0.037303483074728215,
|
||||
-0.055218682902701585,
|
||||
-0.07226305111525733,
|
||||
-0.08816778784387092,
|
||||
-0.10268206588930337,
|
||||
-0.11557698641636836,
|
||||
-0.12664918882530235,
|
||||
-0.13572405786990283,
|
||||
-0.142658477444273,
|
||||
-0.14734308760930326,
|
||||
-0.14970400926424074,
|
||||
-0.14970400926424074,
|
||||
-0.14734308760930329,
|
||||
-0.14265847744427307,
|
||||
-0.13572405786990288,
|
||||
-0.12664918882530227,
|
||||
-0.11557698641636828,
|
||||
-0.10268206588930327,
|
||||
-0.08816778784387101,
|
||||
-0.07226305111525745,
|
||||
-0.05521868290270171,
|
||||
-0.03730348307472834,
|
||||
-0.0187999850346456,
|
||||
-7.347880794884119e-17,
|
||||
0.018799985034645455,
|
||||
0.037303483074728194,
|
||||
0.05521868290270157,
|
||||
0.07226305111525731,
|
||||
0.0881677878438709,
|
||||
0.10268206588930336,
|
||||
0.11557698641636836,
|
||||
0.12664918882530232,
|
||||
0.13572405786990294,
|
||||
0.1426584774442731,
|
||||
0.1473430876093033,
|
||||
0.14970400926424074,
|
||||
0.14970400926424074,
|
||||
0.14734308760930329,
|
||||
0.14265847744427299,
|
||||
0.13572405786990302,
|
||||
0.12664918882530243,
|
||||
0.11557698641636846,
|
||||
0.10268206588930347,
|
||||
0.08816778784387104,
|
||||
0.07226305111525747,
|
||||
0.05521868290270173,
|
||||
0.037303483074728354,
|
||||
0.01879998503464562,
|
||||
9.18485099360515e-17,
|
||||
-0.018799985034645438,
|
||||
-0.03730348307472817,
|
||||
-0.0552186829027018,
|
||||
-0.0722630511152573,
|
||||
-0.08816778784387089,
|
||||
-0.10268206588930313,
|
||||
-0.11557698641636852,
|
||||
-0.12664918882530232,
|
||||
-0.13572405786990294,
|
||||
-0.142658477444273,
|
||||
-0.14734308760930334,
|
||||
-0.14970400926424074,
|
||||
-0.14970400926424074,
|
||||
-0.1473430876093033,
|
||||
-0.14265847744427307,
|
||||
-0.13572405786990302,
|
||||
-0.12664918882530243,
|
||||
-0.11557698641636865,
|
||||
-0.10268206588930329,
|
||||
-0.08816778784387105,
|
||||
-0.07226305111525748,
|
||||
-0.055218682902701995,
|
||||
-0.03730348307472811,
|
||||
-0.01879998503464564,
|
||||
-1.1021821192326178e-16,
|
||||
0.01879998503464542,
|
||||
0.0373034830747279,
|
||||
0.055218682902701786,
|
||||
0.07226305111525728,
|
||||
0.08816778784387087,
|
||||
0.10268206588930313,
|
||||
0.11557698641636852,
|
||||
0.1266491888253023,
|
||||
0.1357240578699029,
|
||||
0.14265847744427299,
|
||||
0.14734308760930334,
|
||||
0.14970400926424074,
|
||||
0.14970400926424074,
|
||||
0.1473430876093033,
|
||||
0.14265847744427307,
|
||||
0.1357240578699028,
|
||||
0.12664918882530243,
|
||||
0.11557698641636867,
|
||||
0.1026820658893033,
|
||||
0.08816778784387107,
|
||||
0.07226305111525749,
|
||||
0.05521868290270201,
|
||||
0.03730348307472813,
|
||||
0.01879998503464566,
|
||||
1.2858791391047207e-16,
|
||||
-0.0187999850346454,
|
||||
-0.03730348307472788,
|
||||
-0.05521868290270177,
|
||||
-0.07226305111525726,
|
||||
-0.08816778784387087,
|
||||
-0.10268206588930312,
|
||||
-0.1155769864163685,
|
||||
-0.1266491888253023,
|
||||
-0.1357240578699029,
|
||||
-0.14265847744427299,
|
||||
-0.14734308760930334,
|
||||
-0.14970400926424074,
|
||||
-0.14970400926424074,
|
||||
-0.1473430876093033,
|
||||
-0.14265847744427307,
|
||||
-0.1357240578699028,
|
||||
-0.12664918882530243,
|
||||
-0.11557698641636868,
|
||||
-0.10268206588930333,
|
||||
-0.08816778784387108,
|
||||
-0.0722630511152575,
|
||||
-0.05521868290270203,
|
||||
-0.03730348307472815,
|
||||
-0.018799985034645677,
|
||||
-1.4695761589768238e-16,
|
||||
0.01856644786983349,
|
||||
0.03638245679596323,
|
||||
0.0531863271257785,
|
||||
0.06873874052503183,
|
||||
0.08282597161989906,
|
||||
0.09526261779156023,
|
||||
0.10589381608321365,
|
||||
0.11459692501303523,
|
||||
0.1212826580513477,
|
||||
0.12589566447200526,
|
||||
0.1284145620861484,
|
||||
0.12885143487654274,
|
||||
0.12725081664585672,
|
||||
0.12368818935544204,
|
||||
0.11826803175658426,
|
||||
0.1111214601106251,
|
||||
0.10240350817844192,
|
||||
0.0922900981688023,
|
||||
0.08097475791981867,
|
||||
0.06866514221447995,
|
||||
0.055579417782458194,
|
||||
0.04194257221409126,
|
||||
0.027982706722276016,
|
||||
0.013927371462208751,
|
||||
1.2095604965641715e-16,
|
||||
-0.013583503435593256,
|
||||
-0.026617974011402645,
|
||||
-0.038911948171488256,
|
||||
-0.05029033688222117,
|
||||
-0.06059677531980971,
|
||||
-0.06969562003067588,
|
||||
-0.07747357085528037,
|
||||
-0.08384090136876289,
|
||||
-0.08873228815055724,
|
||||
-0.0921072357443415,
|
||||
-0.09395010060656506,
|
||||
-0.09426972356787908,
|
||||
-0.09309868625433226,
|
||||
-0.09049221244855306,
|
||||
-0.08652674043787481,
|
||||
-0.08129819692830416,
|
||||
-0.07492000704231337,
|
||||
-0.06752087821731563,
|
||||
-0.05924239844431021,
|
||||
-0.05023649120795737,
|
||||
-0.04066277069740133,
|
||||
-0.030685841350052333,
|
||||
-0.020472585578247403,
|
||||
-0.010189482631897374,
|
||||
-9.832592927142318e-17,
|
||||
0.009937903409330418,
|
||||
0.019474125797637704,
|
||||
0.0284685894350225,
|
||||
0.03679319644802473,
|
||||
0.044333547887740916,
|
||||
0.05099040488356929,
|
||||
0.056680875268027994,
|
||||
0.06133931378636083,
|
||||
0.06491792880314469,
|
||||
0.06738709320963301,
|
||||
0.06873536194487236,
|
||||
0.06896920309873988,
|
||||
0.06811245389806937,
|
||||
0.06620551692532123,
|
||||
0.06330431562615867,
|
||||
0.05947903147792919,
|
||||
0.05481264807294881,
|
||||
0.04939932978399098,
|
||||
0.043342664598141574,
|
||||
0.03675380211118236,
|
||||
0.029749518558492356,
|
||||
0.02245024111907521,
|
||||
0.014978063573993635,
|
||||
0.007454784744376489,
|
||||
2.878198652327287e-16,
|
||||
-0.0072707254532282444,
|
||||
-0.014247574793624922,
|
||||
-0.0208280649647277,
|
||||
-0.02691847756027895,
|
||||
-0.03243511652132547,
|
||||
-0.03730537713913632,
|
||||
-0.04146861420846457,
|
||||
-0.04487680063496369,
|
||||
-0.04749497131122594,
|
||||
-0.049301450581451696,
|
||||
-0.05028786506017283,
|
||||
-0.05045894690303327,
|
||||
-0.049832135797735155,
|
||||
-0.04843699090505647,
|
||||
-0.04631442669186875,
|
||||
-0.04351578902386234,
|
||||
-0.04010178999412147,
|
||||
-0.03614132172945704,
|
||||
-0.03171017082019282,
|
||||
-0.02688965604775296,
|
||||
-0.021765212731031044,
|
||||
-0.016424947276336123,
|
||||
-0.010958185402089994,
|
||||
-0.005454037029418993,
|
||||
-6.3156092834735e-17,
|
||||
0.005319376375362082,
|
||||
0.01042374839360207,
|
||||
0.015238137848910902,
|
||||
0.01969397889054942,
|
||||
0.023730038173707255,
|
||||
0.027293196958740988,
|
||||
0.03033908626567152,
|
||||
0.03283256872166209,
|
||||
0.034748063307665326,
|
||||
0.03606971177513051,
|
||||
0.03679138802438222,
|
||||
0.03691655417444788,
|
||||
0.03645796937341448,
|
||||
0.035437259565285636,
|
||||
0.03388435841347474,
|
||||
0.03183683135580237,
|
||||
0.029339096308435262,
|
||||
0.026441555828059723,
|
||||
0.023199656568620733,
|
||||
0.01967289262153575,
|
||||
0.015923769801370835,
|
||||
0.01201674813199198,
|
||||
0.008017179705064093,
|
||||
0.003990258731576542,
|
||||
-6.164690305841934e-17,
|
||||
-0.003891738892464325,
|
||||
-0.007626177236966827,
|
||||
-0.011148459806306474,
|
||||
-0.014408422752471289,
|
||||
-0.017361266803384564,
|
||||
-0.01996812945893378,
|
||||
-0.022196549679925754,
|
||||
-0.024020820415232586,
|
||||
-0.025422226191515247,
|
||||
-0.026389164866286233,
|
||||
-0.026917154489278325,
|
||||
-0.027008728000881468,
|
||||
-0.02667322019324803,
|
||||
-0.025926452945001868,
|
||||
-0.02479032619212772,
|
||||
-0.02329232339604356,
|
||||
-0.021464941398422012,
|
||||
-0.0193450554974736,
|
||||
-0.016973231331797612,
|
||||
-0.014392995708504558,
|
||||
-0.011650078858431393,
|
||||
-0.008791640742480778,
|
||||
-0.005865493972298641,
|
||||
-0.002919335651562286,
|
||||
-3.943919054879792e-17,
|
||||
0.0028472569975064722,
|
||||
0.0055794304556819685,
|
||||
0.008156387432977339,
|
||||
0.010541427274178315,
|
||||
0.012701774131668711,
|
||||
0.014608995592985858,
|
||||
0.016239342654524213,
|
||||
0.01757400763590476,
|
||||
0.01859929800432925,
|
||||
0.019306725451024603,
|
||||
0.019693010911127292,
|
||||
0.01976000752341367,
|
||||
0.019514544767715435,
|
||||
0.018968198177713044,
|
||||
0.018136990088845957,
|
||||
0.01704102783102496,
|
||||
0.015704086601509296,
|
||||
0.014153144944791883,
|
||||
0.012417881316069912,
|
||||
0.010530140607703934,
|
||||
0.008523379771289316,
|
||||
0.00643210177128294,
|
||||
0.004291287061626068,
|
||||
0.0021358315888240385,
|
||||
9.070586579183172e-17,
|
||||
-0.0020830977190033637,
|
||||
-0.004081998521997866,
|
||||
-0.005967340521710147,
|
||||
-0.007712272945193301,
|
||||
-0.009292816470078945,
|
||||
-0.010688169499041026,
|
||||
-0.011880956889869792,
|
||||
-0.012857418649655518,
|
||||
-0.013607537107403339,
|
||||
-0.014125102083751515,
|
||||
-0.014407714563597466,
|
||||
-0.01445673033223267,
|
||||
-0.014277145943839522,
|
||||
-0.013877430239772084,
|
||||
-0.01326930541105003,
|
||||
-0.012467482294492575,
|
||||
-0.01148935519599578,
|
||||
-0.010354662040356868,
|
||||
-0.009085116049241277,
|
||||
-0.00770401544360185,
|
||||
-0.006235837852122879,
|
||||
-0.004705826182846021,
|
||||
-0.003139572682582101,
|
||||
-0.0015626077711816495
|
||||
],
|
||||
"file_path": null
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
0.0,
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"node_id": 4,
|
||||
"forces": [
|
||||
0.0,
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "GroundMotion",
|
||||
"type": "UniformExcitation",
|
||||
"direction": 1,
|
||||
"accel_series_id": 2,
|
||||
"vel_series_id": null,
|
||||
"disp_series_id": null,
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Earthquake",
|
||||
"type": "Transient",
|
||||
"pattern_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"dt": 0.01,
|
||||
"n_steps": 400,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"integrator": "Newmark",
|
||||
"integrator_params": [
|
||||
0.5,
|
||||
0.25
|
||||
],
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-12,
|
||||
"max_iter": 10,
|
||||
"rayleigh_alpha_m": 0.0,
|
||||
"rayleigh_beta_k": 0.000625
|
||||
}
|
||||
]
|
||||
}
|
||||
161
examples/rc_frame_earthquake.py
Normal file
161
examples/rc_frame_earthquake.py
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
"""RC Frame Earthquake Analysis — OpenSees Examples Manual, Example 3.3.
|
||||
|
||||
Time-history analysis of the RC portal frame under horizontal ground
|
||||
motion. Sources the Example 3 gravity model, adds lumped joint
|
||||
masses, a PathTimeSeries from a ground-motion record, a
|
||||
UniformExcitation load pattern in +X, and stiffness-proportional
|
||||
Rayleigh damping. Newmark integrator with average-acceleration
|
||||
(gamma = 0.5, beta = 0.25).
|
||||
|
||||
Matches the Tcl walkthrough at:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=RC_Portal_Frame_Earthquake_Analysis
|
||||
|
||||
Model (kip-in-ksi):
|
||||
- Geometry + section + elements = Example 3 (rc_frame_gravity).
|
||||
- Gravity pattern uses ConstantTimeSeries so it stays locked during
|
||||
the transient (equivalent to ``loadConst -time 0.0``).
|
||||
- Nodal masses: m = P/g = 180/386.4 kip·s^2/in at nodes 3 and 4.
|
||||
- Ground-motion record: since the Tcl ships ARL360.at2 from the
|
||||
PEER strong-motion database (not redistributable without
|
||||
attribution), we bundle a short synthetic acceleration record
|
||||
that reproduces the same classroom behaviour: a ~4-second
|
||||
pulse-like time history with peak amplitude ≈ 0.35 g.
|
||||
- UniformExcitation pattern in DOF 1 (+X), scale factor = g
|
||||
(so the path data is in "g" units, multiplied to in/s²).
|
||||
- Rayleigh damping: alpha_m = 0, beta_kcommit = 0.000625.
|
||||
|
||||
GUI walkthrough: File → Open → rc_frame_earthquake.osmodel → Analyze
|
||||
→ Run → Earthquake → Display → Show Time-History Plot (Node 3 Ux).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
ConstantTimeSeries,
|
||||
NodalLoad,
|
||||
PathTimeSeries,
|
||||
PlainLoadPattern,
|
||||
TransientCase,
|
||||
UniformExcitationPattern,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
try:
|
||||
from examples.rc_frame_gravity import build_rc_frame_gravity, P_LOAD
|
||||
except ImportError:
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from rc_frame_gravity import build_rc_frame_gravity, P_LOAD # type: ignore
|
||||
|
||||
|
||||
G = 386.4 # in/s² (gravity)
|
||||
DT = 0.01 # s — time step of bundled ground motion
|
||||
N_PTS = 400 # 4-second duration
|
||||
BETA_K_COMMIT = 0.000625 # Tcl reference stiffness-damping coeff
|
||||
|
||||
|
||||
def _synthetic_ground_motion() -> list[float]:
|
||||
"""Bundle a short acceleration signal (units of g).
|
||||
|
||||
Decaying sinusoid centred at ~2 Hz with an exponential envelope —
|
||||
peak ~0.15 g, enough to drive the fibre section into inelastic
|
||||
cycles without blowing past its crushing strain on the very first
|
||||
impulse (which would require a much tighter Newmark step).
|
||||
"""
|
||||
out: list[float] = []
|
||||
peak = 0.15 # units of g
|
||||
freq = 2.0 # Hz (period ~0.5 s)
|
||||
for i in range(N_PTS):
|
||||
t = i * DT
|
||||
if t < 0.5:
|
||||
env = t / 0.5
|
||||
elif t < 2.0:
|
||||
env = 1.0
|
||||
else:
|
||||
env = math.exp(-(t - 2.0) / 0.8)
|
||||
out.append(peak * env * math.sin(2.0 * math.pi * freq * t))
|
||||
return out
|
||||
|
||||
|
||||
def build_rc_frame_earthquake(): # type: ignore[no-untyped-def]
|
||||
"""Ex 3 gravity + lumped masses + ground motion + Rayleigh damping."""
|
||||
proj = build_rc_frame_gravity()
|
||||
proj.meta.name = "RC Frame Earthquake (OpenSees Ex 3.3)"
|
||||
proj.meta.description = (
|
||||
"Ex 3 gravity + uniform base excitation (horizontal, 4-s "
|
||||
"synthetic record peaking at ~0.35 g) + Rayleigh beta_k"
|
||||
)
|
||||
|
||||
# Locked-in gravity — Constant TS, matches the Tcl loadConst.
|
||||
proj.time_series = [
|
||||
ConstantTimeSeries(id=1, name="Gravity"),
|
||||
PathTimeSeries(
|
||||
id=2, name="GroundMotion",
|
||||
dt=DT, factor=G,
|
||||
values=_synthetic_ground_motion(),
|
||||
),
|
||||
]
|
||||
|
||||
# Lumped mass m = P/g at each top node (gravity is the sole
|
||||
# tributary weight; m_x = m_y because a point mass is isotropic).
|
||||
m = P_LOAD / G # ≈ 0.466 kip·s²/in
|
||||
for n in proj.nodes:
|
||||
if n.id in (3, 4):
|
||||
n.mass = (m, m, 0.0, 0.0, 0.0, 0.0)
|
||||
|
||||
# Gravity pattern (now with Constant TS).
|
||||
proj.load_patterns = [
|
||||
PlainLoadPattern(
|
||||
id=1, name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=3, forces=(0, -P_LOAD, 0, 0, 0, 0)),
|
||||
NodalLoad(node_id=4, forces=(0, -P_LOAD, 0, 0, 0, 0)),
|
||||
],
|
||||
),
|
||||
# Ground motion — applied as UniformExcitation in +X (dir=1).
|
||||
UniformExcitationPattern(
|
||||
id=2, name="GroundMotion",
|
||||
direction=1,
|
||||
accel_series_id=2,
|
||||
),
|
||||
]
|
||||
|
||||
proj.analyses = [TransientCase(
|
||||
id=1, name="Earthquake",
|
||||
pattern_ids=[1, 2],
|
||||
dt=DT,
|
||||
n_steps=N_PTS,
|
||||
system="BandGeneral", constraints="Plain",
|
||||
integrator="Newmark",
|
||||
integrator_params=(0.5, 0.25), # average-acceleration method
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr", tolerance=1e-12, max_iter=10,
|
||||
rayleigh_alpha_m=0.0,
|
||||
rayleigh_beta_k=BETA_K_COMMIT,
|
||||
)]
|
||||
return proj
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_rc_frame_earthquake()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" Ground motion: {N_PTS} points, dt = {DT} s, "
|
||||
f"total = {N_PTS * DT:.2f} s")
|
||||
print(f" Nodal mass (3, 4): {P_LOAD / G:.4f} kip*s^2/in")
|
||||
print(f" Rayleigh beta_k = {BETA_K_COMMIT}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
422
examples/rc_frame_gravity.osmodel
Normal file
422
examples/rc_frame_gravity.osmodel
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "RC Frame Gravity (OpenSees Ex 3)",
|
||||
"description": "1-bay 1-storey portal frame, nonlinear fibre columns + elastic beam, 10-step LoadControl gravity pushdown.",
|
||||
"author": "OpenSees Examples Manual",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [
|
||||
{
|
||||
"id": "X1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X2",
|
||||
"ordinate": 360.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"y_grid_lines": [
|
||||
{
|
||||
"id": "Y1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y2",
|
||||
"ordinate": 144.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"z_grid_lines": [
|
||||
{
|
||||
"id": "Z1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Base-R",
|
||||
"coords": [
|
||||
360.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Top-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Top-R",
|
||||
"coords": [
|
||||
360.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Core-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -6.0,
|
||||
"epsc0": -0.004,
|
||||
"fpcu": -5.0,
|
||||
"epsU": -0.014
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Cover-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -5.0,
|
||||
"epsc0": -0.002,
|
||||
"fpcu": 0.0,
|
||||
"epsU": -0.006
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Steel-60",
|
||||
"type": "Steel01",
|
||||
"Fy": 60.0,
|
||||
"E0": 30000.0,
|
||||
"b": 0.01,
|
||||
"a1": null,
|
||||
"a2": null,
|
||||
"a3": null,
|
||||
"a4": null
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "RC-Col",
|
||||
"type": "FiberSection",
|
||||
"GJ": null,
|
||||
"patches": [
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 1,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": 6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 7.5
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -7.5,
|
||||
"y_j": 12.0,
|
||||
"z_j": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -6.0,
|
||||
"y_j": -10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": 10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 6.0
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": 10.5,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 2,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 0.0,
|
||||
"z_start": 6.0,
|
||||
"y_end": 0.0,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": -10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": -10.5,
|
||||
"z_end": -6.0
|
||||
}
|
||||
],
|
||||
"fibres": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Beam",
|
||||
"type": "ElasticSection",
|
||||
"E": 4030.0,
|
||||
"A": 360.0,
|
||||
"Iz": 8640.0,
|
||||
"Iy": 8640.0,
|
||||
"G": 1500.0,
|
||||
"J": 1.0
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col-L",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-R",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Beam",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
0.0,
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"node_id": 4,
|
||||
"forces": [
|
||||
0.0,
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 10,
|
||||
"load_factor_increment": 0.1,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Transformation",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-12,
|
||||
"max_iter": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
232
examples/rc_frame_gravity.py
Normal file
232
examples/rc_frame_gravity.py
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
"""RC Frame Gravity Analysis — OpenSees Examples Manual, Example 3.
|
||||
|
||||
Single-bay, single-storey RC portal frame under gravity (two 180-kip
|
||||
nodal loads on top joints). Columns are nonlinear forceBeamColumn
|
||||
elements with the fibre section from the Moment-Curvature example;
|
||||
the beam is an elasticBeamColumn with stiffness (A, E, Iz) =
|
||||
(360, 4030, 8640) — matching the Tcl reference at:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=RC_Portal_Frame
|
||||
|
||||
Model (kip-in-ksi):
|
||||
node 3 ─────── elasticBeam 3 ─────── node 4
|
||||
│ │
|
||||
forceBC 1 forceBC 2
|
||||
│ │
|
||||
node 1 node 2
|
||||
(fixed) (fixed)
|
||||
|
||||
Width 360", height 144", columns fibre-section RC (Concrete01 +
|
||||
Steel01). Load pattern: 180 kip ↓ at each top node, Linear time series,
|
||||
LoadControl 0.1 × 10 steps = full gravity.
|
||||
|
||||
Expected terminal state (nodes 3 & 4): Uy ≈ -0.0203 in, Ux ≈ 0,
|
||||
column axial force ≈ 180 kip compression.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
Concrete01,
|
||||
CoordinateGridSystem,
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
FiberSection,
|
||||
ForceBeamColumn,
|
||||
GridSystem,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
RectangularPatch,
|
||||
StaticCase,
|
||||
Steel01,
|
||||
StraightLayer,
|
||||
UnitSystem,
|
||||
make_grid_lines,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
# Frame geometry (inches).
|
||||
WIDTH = 360.0
|
||||
HEIGHT = 144.0
|
||||
|
||||
# Column section parameters (same as Moment-Curvature example).
|
||||
COL_WIDTH = 15.0
|
||||
COL_DEPTH = 24.0
|
||||
COVER = 1.5
|
||||
AS_BAR = 0.60
|
||||
|
||||
# Material properties (kip, in, ksi).
|
||||
CONC_CORE_FPC = -6.0
|
||||
CONC_COVER_FPC = -5.0
|
||||
STEEL_FY = 60.0
|
||||
# Steel Young's modulus: 30000 ksi (matches OpenSees Wiki, which sources
|
||||
# the MK example's $E = 30000). Some Tcl reprints show 3000 — that's a
|
||||
# typo; 3000 gives Uy ≈ -0.0203 instead of the reference -0.01837.
|
||||
STEEL_E = 30000.0
|
||||
STEEL_B = 0.01
|
||||
|
||||
# Beam elastic properties.
|
||||
BEAM_A = 360.0
|
||||
BEAM_E = 4030.0
|
||||
BEAM_IZ = 8640.0
|
||||
|
||||
# Gravity load.
|
||||
P_LOAD = 180.0 # kip, pointing -Y (compression on columns)
|
||||
|
||||
|
||||
def build_rc_frame_gravity() -> Project:
|
||||
y1 = COL_DEPTH / 2.0 # 12
|
||||
z1 = COL_WIDTH / 2.0 # 7.5
|
||||
|
||||
return Project(
|
||||
meta=ProjectMeta(
|
||||
name="RC Frame Gravity (OpenSees Ex 3)",
|
||||
author="OpenSees Examples Manual",
|
||||
description=(
|
||||
"1-bay 1-storey portal frame, nonlinear fibre columns + "
|
||||
"elastic beam, 10-step LoadControl gravity pushdown."
|
||||
),
|
||||
units=UnitSystem.US_IN_KIP,
|
||||
),
|
||||
ndm=2, ndf=3,
|
||||
coord_systems=[
|
||||
CoordinateGridSystem(
|
||||
name="Global",
|
||||
grid=GridSystem(
|
||||
x_grid_lines=make_grid_lines("X", [0.0, WIDTH]),
|
||||
y_grid_lines=make_grid_lines("Y", [0.0, HEIGHT]),
|
||||
z_grid_lines=make_grid_lines("Z", [0.0]),
|
||||
),
|
||||
),
|
||||
],
|
||||
nodes=[
|
||||
Node(id=1, name="Base-L",
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True)),
|
||||
Node(id=2, name="Base-R",
|
||||
coords=(WIDTH, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True)),
|
||||
Node(id=3, name="Top-L", coords=(0.0, HEIGHT, 0.0)),
|
||||
Node(id=4, name="Top-R", coords=(WIDTH, HEIGHT, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
Concrete01(id=1, name="Core-Conc",
|
||||
fpc=CONC_CORE_FPC, epsc0=-0.004,
|
||||
fpcu=-5.0, epsU=-0.014),
|
||||
Concrete01(id=2, name="Cover-Conc",
|
||||
fpc=CONC_COVER_FPC, epsc0=-0.002,
|
||||
fpcu=0.0, epsU=-0.006),
|
||||
Steel01(id=3, name="Steel-60",
|
||||
Fy=STEEL_FY, E0=STEEL_E, b=STEEL_B),
|
||||
],
|
||||
sections=[
|
||||
# Fibre section for the columns (MK recipe).
|
||||
FiberSection(
|
||||
id=1, name="RC-Col",
|
||||
patches=[
|
||||
RectangularPatch(
|
||||
material_id=1, n_fib_y=10, n_fib_z=1,
|
||||
y_i=COVER - y1, z_i=COVER - z1,
|
||||
y_j=y1 - COVER, z_j=z1 - COVER,
|
||||
),
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=10, n_fib_z=1,
|
||||
y_i=-y1, z_i=z1 - COVER,
|
||||
y_j=y1, z_j=z1,
|
||||
),
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=10, n_fib_z=1,
|
||||
y_i=-y1, z_i=-z1,
|
||||
y_j=y1, z_j=COVER - z1,
|
||||
),
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=2, n_fib_z=1,
|
||||
y_i=-y1, z_i=COVER - z1,
|
||||
y_j=COVER - y1, z_j=z1 - COVER,
|
||||
),
|
||||
RectangularPatch(
|
||||
material_id=2, n_fib_y=2, n_fib_z=1,
|
||||
y_i=y1 - COVER, z_i=COVER - z1,
|
||||
y_j=y1, z_j=z1 - COVER,
|
||||
),
|
||||
],
|
||||
layers=[
|
||||
StraightLayer(
|
||||
material_id=3, n_bars=3, bar_area=AS_BAR,
|
||||
y_start=y1 - COVER, z_start=z1 - COVER,
|
||||
y_end=y1 - COVER, z_end=COVER - z1,
|
||||
),
|
||||
StraightLayer(
|
||||
material_id=3, n_bars=2, bar_area=AS_BAR,
|
||||
y_start=0.0, z_start=z1 - COVER,
|
||||
y_end=0.0, z_end=COVER - z1,
|
||||
),
|
||||
StraightLayer(
|
||||
material_id=3, n_bars=3, bar_area=AS_BAR,
|
||||
y_start=COVER - y1, z_start=z1 - COVER,
|
||||
y_end=COVER - y1, z_end=COVER - z1,
|
||||
),
|
||||
],
|
||||
),
|
||||
# Elastic section for the beam.
|
||||
ElasticSection(
|
||||
id=2, name="Beam",
|
||||
E=BEAM_E, A=BEAM_A, Iz=BEAM_IZ,
|
||||
Iy=BEAM_IZ, G=1500.0, J=1.0, # placeholders for 3D round-trip
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
# Columns — fibre-section forceBeamColumn.
|
||||
ForceBeamColumn(id=1, name="Col-L",
|
||||
nodes=(1, 3), section_id=1,
|
||||
integration_points=5, geom_transf="Linear"),
|
||||
ForceBeamColumn(id=2, name="Col-R",
|
||||
nodes=(2, 4), section_id=1,
|
||||
integration_points=5, geom_transf="Linear"),
|
||||
# Beam — elastic.
|
||||
ElasticBeamColumn(id=3, name="Beam",
|
||||
nodes=(3, 4), section_id=2,
|
||||
geom_transf="Linear"),
|
||||
],
|
||||
time_series=[LinearTimeSeries(id=1, name="Gravity")],
|
||||
load_patterns=[PlainLoadPattern(
|
||||
id=1, name="Gravity", time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=3, forces=(0, -P_LOAD, 0, 0, 0, 0)),
|
||||
NodalLoad(node_id=4, forces=(0, -P_LOAD, 0, 0, 0, 0)),
|
||||
],
|
||||
)],
|
||||
analyses=[StaticCase(
|
||||
id=1, name="Gravity",
|
||||
pattern_ids=[1],
|
||||
n_steps=10, load_factor_increment=0.1,
|
||||
system="BandGeneral", constraints="Transformation",
|
||||
integrator="LoadControl", algorithm="Newton",
|
||||
test="NormDispIncr", tolerance=1e-12, max_iter=10,
|
||||
)],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_rc_frame_gravity()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" ndm={project.ndm}, ndf={project.ndf}, units={project.meta.units.value}")
|
||||
print(f" Frame: {WIDTH}in x {HEIGHT}in, P = -{P_LOAD} kip at each top node")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
484
examples/rc_frame_pushover.osmodel
Normal file
484
examples/rc_frame_pushover.osmodel
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "RC Frame Pushover (OpenSees Ex 3.2)",
|
||||
"description": "Ex 3 gravity preload (StaticCase) + lateral reference load + DisplacementControl pushover on node 3 (DOF 1) to 15 in, chained via preload_case_ids.",
|
||||
"author": "OpenSees Examples Manual",
|
||||
"units": "US (in, kip, kip·s²/in, s, ksi)"
|
||||
},
|
||||
"ndm": 2,
|
||||
"ndf": 3,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [
|
||||
{
|
||||
"id": "X1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "X2",
|
||||
"ordinate": 360.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"y_grid_lines": [
|
||||
{
|
||||
"id": "Y1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
},
|
||||
{
|
||||
"id": "Y2",
|
||||
"ordinate": 144.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"z_grid_lines": [
|
||||
{
|
||||
"id": "Z1",
|
||||
"ordinate": 0.0,
|
||||
"line_type": "Primary",
|
||||
"visible": true,
|
||||
"bubble_loc": "End",
|
||||
"color": "#808080"
|
||||
}
|
||||
],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Base-R",
|
||||
"coords": [
|
||||
360.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Top-L",
|
||||
"coords": [
|
||||
0.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Top-R",
|
||||
"coords": [
|
||||
360.0,
|
||||
144.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Core-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -6.0,
|
||||
"epsc0": -0.004,
|
||||
"fpcu": -5.0,
|
||||
"epsU": -0.014
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Cover-Conc",
|
||||
"type": "Concrete01",
|
||||
"fpc": -5.0,
|
||||
"epsc0": -0.002,
|
||||
"fpcu": 0.0,
|
||||
"epsU": -0.006
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Steel-60",
|
||||
"type": "Steel01",
|
||||
"Fy": 60.0,
|
||||
"E0": 30000.0,
|
||||
"b": 0.01,
|
||||
"a1": null,
|
||||
"a2": null,
|
||||
"a3": null,
|
||||
"a4": null
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "RC-Col",
|
||||
"type": "FiberSection",
|
||||
"GJ": null,
|
||||
"patches": [
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 1,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": 6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 7.5
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 10,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -7.5,
|
||||
"y_j": 12.0,
|
||||
"z_j": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": -12.0,
|
||||
"z_i": -6.0,
|
||||
"y_j": -10.5,
|
||||
"z_j": 6.0
|
||||
},
|
||||
{
|
||||
"kind": "rect",
|
||||
"material_id": 2,
|
||||
"n_fib_y": 2,
|
||||
"n_fib_z": 1,
|
||||
"y_i": 10.5,
|
||||
"z_i": -6.0,
|
||||
"y_j": 12.0,
|
||||
"z_j": 6.0
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": 10.5,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 2,
|
||||
"bar_area": 0.6,
|
||||
"y_start": 0.0,
|
||||
"z_start": 6.0,
|
||||
"y_end": 0.0,
|
||||
"z_end": -6.0
|
||||
},
|
||||
{
|
||||
"kind": "straight",
|
||||
"material_id": 3,
|
||||
"n_bars": 3,
|
||||
"bar_area": 0.6,
|
||||
"y_start": -10.5,
|
||||
"z_start": 6.0,
|
||||
"y_end": -10.5,
|
||||
"z_end": -6.0
|
||||
}
|
||||
],
|
||||
"fibres": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Beam",
|
||||
"type": "ElasticSection",
|
||||
"E": 4030.0,
|
||||
"A": 360.0,
|
||||
"Iz": 8640.0,
|
||||
"Iy": 8640.0,
|
||||
"G": 1500.0,
|
||||
"J": 1.0
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col-L",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
3
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Col-R",
|
||||
"type": "ForceBeamColumn",
|
||||
"nodes": [
|
||||
2,
|
||||
4
|
||||
],
|
||||
"section_id": 1,
|
||||
"integration_points": 5,
|
||||
"geom_transf": "Linear",
|
||||
"max_iter": 10,
|
||||
"tolerance": 1e-12
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Beam",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
3,
|
||||
4
|
||||
],
|
||||
"section_id": 2,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Lateral",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Gravity",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
0.0,
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"node_id": 4,
|
||||
"forces": [
|
||||
0.0,
|
||||
-180.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Lateral",
|
||||
"type": "Plain",
|
||||
"time_series_id": 2,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 3,
|
||||
"forces": [
|
||||
10.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"node_id": 4,
|
||||
"forces": [
|
||||
10.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 100,
|
||||
"name": "Gravity-Preload",
|
||||
"type": "Static",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"n_steps": 10,
|
||||
"load_factor_increment": 0.1,
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Transformation",
|
||||
"integrator": "LoadControl",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-12,
|
||||
"max_iter": 10
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Pushover",
|
||||
"type": "Pushover",
|
||||
"pattern_ids": [
|
||||
2
|
||||
],
|
||||
"control_node": 3,
|
||||
"control_dof": 1,
|
||||
"target_disp": 15.0,
|
||||
"step_size": 0.1,
|
||||
"base_nodes": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Transformation",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-12,
|
||||
"max_iter": 10,
|
||||
"preload_case_ids": [
|
||||
100
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
139
examples/rc_frame_pushover.py
Normal file
139
examples/rc_frame_pushover.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
"""RC Frame Pushover Analysis — OpenSees Examples Manual, Example 3.2.
|
||||
|
||||
Sources the Example 3 gravity model and extends it with a lateral
|
||||
reference load pattern + DisplacementControl pushover on the top-left
|
||||
joint (node 3, DOF 1 = Ux). Target displacement 15 in with dU = 0.1
|
||||
in per step. Matches the Tcl walkthrough at:
|
||||
https://opensees.berkeley.edu/wiki/index.php?title=RC_Portal_Frame_Pushover_Analysis
|
||||
|
||||
Model (kip-in-ksi):
|
||||
- Geometry + section + elements = Example 3 (rc_frame_gravity).
|
||||
- Gravity preload = a ``StaticCase`` with 10 × LoadControl(0.1)
|
||||
steps under a Linear TS — same recipe the Tcl uses
|
||||
(``analyze 10; loadConst -time 0.0``). Referenced by the
|
||||
PushoverCase via ``preload_case_ids``.
|
||||
- Lateral pattern: H = 10 kip at nodes 3 and 4 in +X, Linear TS,
|
||||
scaled by DisplacementControl.
|
||||
|
||||
GUI walkthrough: File → Open → rc_frame_pushover.osmodel → Analyze →
|
||||
Run → Pushover → Display → Show Pushover Curve.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
PlainLoadPattern,
|
||||
PushoverCase,
|
||||
StaticCase,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
# Reuse the Example 3 gravity project as the foundation — identical
|
||||
# geometry, materials, sections, elements. Only the load patterns and
|
||||
# analysis case change for the pushover. Works both when importing as
|
||||
# ``examples.rc_frame_pushover`` (pytest) and when running this file
|
||||
# directly (``python examples/rc_frame_pushover.py``).
|
||||
try:
|
||||
from examples.rc_frame_gravity import build_rc_frame_gravity, P_LOAD
|
||||
except ImportError:
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from rc_frame_gravity import build_rc_frame_gravity, P_LOAD # type: ignore
|
||||
|
||||
# Pushover parameters from the Tcl reference.
|
||||
H_LATERAL = 10.0 # kip — reference lateral load
|
||||
D_STEP = 0.1 # in — DisplacementControl increment
|
||||
D_TARGET = 15.0 # in — total pushover displacement
|
||||
|
||||
|
||||
def build_rc_frame_pushover(): # type: ignore[no-untyped-def]
|
||||
"""Start from the Ex3 gravity model and re-plumb for pushover.
|
||||
|
||||
Three edits to the gravity project:
|
||||
1. Add a ``LinearTimeSeries`` + ``PlainLoadPattern`` for the
|
||||
lateral reference load (H = 10 kip at nodes 3 & 4, +X).
|
||||
2. Keep the gravity pattern on its own Linear TS — the preload
|
||||
runs as a 10-step ``LoadControl(0.1)`` ramp, exactly as the
|
||||
Tcl walkthrough does.
|
||||
3. Replace the StaticCase with two cases: a preload ``StaticCase``
|
||||
(id 100) for gravity, and a ``PushoverCase`` whose
|
||||
``preload_case_ids=[100]`` references it. The pushover's own
|
||||
``pattern_ids`` holds only the lateral reference.
|
||||
"""
|
||||
proj = build_rc_frame_gravity()
|
||||
proj.meta.name = "RC Frame Pushover (OpenSees Ex 3.2)"
|
||||
proj.meta.description = (
|
||||
"Ex 3 gravity preload (StaticCase) + lateral reference load + "
|
||||
"DisplacementControl pushover on node 3 (DOF 1) to 15 in, "
|
||||
"chained via preload_case_ids."
|
||||
)
|
||||
|
||||
proj.time_series = [
|
||||
LinearTimeSeries(id=1, name="Gravity"),
|
||||
LinearTimeSeries(id=2, name="Lateral"),
|
||||
]
|
||||
proj.load_patterns = [
|
||||
PlainLoadPattern(
|
||||
id=1, name="Gravity",
|
||||
time_series_id=1,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=3, forces=(0, -P_LOAD, 0, 0, 0, 0)),
|
||||
NodalLoad(node_id=4, forces=(0, -P_LOAD, 0, 0, 0, 0)),
|
||||
],
|
||||
),
|
||||
# Lateral reference — scaled by the DisplacementControl factor.
|
||||
PlainLoadPattern(
|
||||
id=2, name="Lateral",
|
||||
time_series_id=2,
|
||||
nodal_loads=[
|
||||
NodalLoad(node_id=3, forces=(H_LATERAL, 0, 0, 0, 0, 0)),
|
||||
NodalLoad(node_id=4, forces=(H_LATERAL, 0, 0, 0, 0, 0)),
|
||||
],
|
||||
),
|
||||
]
|
||||
proj.analyses = [
|
||||
StaticCase(
|
||||
id=100, name="Gravity-Preload",
|
||||
pattern_ids=[1],
|
||||
n_steps=10, load_factor_increment=0.1,
|
||||
system="BandGeneral", constraints="Transformation",
|
||||
integrator="LoadControl", algorithm="Newton",
|
||||
test="NormDispIncr", tolerance=1e-12, max_iter=10,
|
||||
),
|
||||
PushoverCase(
|
||||
id=1, name="Pushover",
|
||||
preload_case_ids=[100],
|
||||
pattern_ids=[2], # lateral only
|
||||
control_node=3, control_dof=1, # Ux at top-left joint
|
||||
target_disp=D_TARGET,
|
||||
step_size=D_STEP,
|
||||
base_nodes=[1, 2],
|
||||
system="BandGeneral", constraints="Transformation",
|
||||
algorithm="Newton",
|
||||
test="NormDispIncr", tolerance=1e-12, max_iter=10,
|
||||
),
|
||||
]
|
||||
return proj
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_rc_frame_pushover()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}'")
|
||||
print(f" H = {H_LATERAL} kip reference, dU = {D_STEP} in, target = {D_TARGET} in")
|
||||
print(f" Steps = {int(D_TARGET / D_STEP)}")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
202
examples/sdof_pushover.osmodel
Normal file
202
examples/sdof_pushover.osmodel
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"meta": {
|
||||
"name": "SDOF Pushover",
|
||||
"description": "",
|
||||
"author": "Ozan",
|
||||
"units": "SI (m, N, kg, s, Pa)"
|
||||
},
|
||||
"ndm": 3,
|
||||
"ndf": 6,
|
||||
"coord_systems": [
|
||||
{
|
||||
"name": "Global",
|
||||
"coord": {
|
||||
"origin": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"rotation_deg": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"grid": {
|
||||
"x_grid_lines": [],
|
||||
"y_grid_lines": [],
|
||||
"z_grid_lines": [],
|
||||
"visible": true,
|
||||
"is_general": false,
|
||||
"hide_all": false,
|
||||
"glue_to_grid": false,
|
||||
"bubble_size": 20
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Base",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"mass": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Top",
|
||||
"coords": [
|
||||
0.0,
|
||||
0.0,
|
||||
3.0
|
||||
],
|
||||
"mass": [
|
||||
5000.0,
|
||||
5000.0,
|
||||
5000.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"restraint": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "HingeSteel",
|
||||
"type": "Hysteretic",
|
||||
"s1p": 50000.0,
|
||||
"e1p": 0.002,
|
||||
"s2p": 150000.0,
|
||||
"e2p": 0.01,
|
||||
"s3p": 165000.0,
|
||||
"e3p": 0.05,
|
||||
"s1n": -50000.0,
|
||||
"e1n": -0.002,
|
||||
"s2n": -150000.0,
|
||||
"e2n": -0.01,
|
||||
"s3n": -165000.0,
|
||||
"e3n": -0.05,
|
||||
"px": 1.0,
|
||||
"py": 1.0,
|
||||
"d1": 0.0,
|
||||
"d2": 0.0,
|
||||
"beta": 0.0
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "W12x40",
|
||||
"type": "ElasticSection",
|
||||
"E": 200000000000.0,
|
||||
"A": 0.0076,
|
||||
"Iz": 0.0002,
|
||||
"Iy": 4.5e-05,
|
||||
"G": 80000000000.0,
|
||||
"J": 8.5e-07
|
||||
}
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Col",
|
||||
"type": "ElasticBeamColumn",
|
||||
"nodes": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"section_id": 1,
|
||||
"geom_transf": "Linear",
|
||||
"rho": 0.0
|
||||
}
|
||||
],
|
||||
"time_series": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Ramp",
|
||||
"type": "Linear",
|
||||
"factor": 1.0
|
||||
}
|
||||
],
|
||||
"load_patterns": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "PushRef",
|
||||
"type": "Plain",
|
||||
"time_series_id": 1,
|
||||
"nodal_loads": [
|
||||
{
|
||||
"node_id": 2,
|
||||
"forces": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"element_loads": []
|
||||
}
|
||||
],
|
||||
"spectra": [],
|
||||
"analyses": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Push-X",
|
||||
"type": "Pushover",
|
||||
"pattern_ids": [
|
||||
1
|
||||
],
|
||||
"control_node": 2,
|
||||
"control_dof": 1,
|
||||
"target_disp": 0.1,
|
||||
"step_size": 0.001,
|
||||
"base_nodes": [
|
||||
1
|
||||
],
|
||||
"system": "BandGeneral",
|
||||
"constraints": "Plain",
|
||||
"algorithm": "Newton",
|
||||
"test": "NormDispIncr",
|
||||
"tolerance": 1e-06,
|
||||
"max_iter": 25
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Modal-3",
|
||||
"type": "Modal",
|
||||
"n_modes": 3,
|
||||
"solver": "genBandArpack"
|
||||
}
|
||||
]
|
||||
}
|
||||
131
examples/sdof_pushover.py
Normal file
131
examples/sdof_pushover.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
"""SDOF cantilever column with a plastic hinge — pushover demo.
|
||||
|
||||
A 3 m steel column fixed at the base. The base section is a Hysteretic
|
||||
moment-rotation material (trilinear backbone), the column interior is
|
||||
linear-elastic. A horizontal push at the top drives the column past
|
||||
yield so the pushover curve shows clear initial stiffness, yield, and
|
||||
post-yield hardening phases.
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
python examples/sdof_pushover.py
|
||||
|
||||
Produces ``examples/sdof_pushover.osmodel``.
|
||||
|
||||
Open in the GUI, run the "Push-X" case, then:
|
||||
|
||||
Display → Show Pushover Curve
|
||||
→ you should see:
|
||||
- linear segment from origin (slope = elastic stiffness)
|
||||
- knee around yield moment / H
|
||||
- post-yield flat-ish segment to the target displacement
|
||||
|
||||
Tip: the model also has a matching gravity-only Static case and a
|
||||
modal case so you can exercise every Display feature on one model.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from otko.core import (
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
HystereticMaterial,
|
||||
LinearTimeSeries,
|
||||
ModalCase,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
ProjectMeta,
|
||||
PushoverCase,
|
||||
UnitSystem,
|
||||
)
|
||||
from otko.services import load_project, save_project
|
||||
|
||||
|
||||
def build_sdof() -> Project:
|
||||
return Project(
|
||||
meta=ProjectMeta(name="SDOF Pushover", author="Ozan",
|
||||
units=UnitSystem.SI_M_N),
|
||||
ndm=3, ndf=6,
|
||||
nodes=[
|
||||
Node(id=1, name="Base", coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True,) * 6),
|
||||
Node(id=2, name="Top", coords=(0.0, 0.0, 3.0),
|
||||
mass=(5_000.0, 5_000.0, 5_000.0, 0.0, 0.0, 0.0)),
|
||||
],
|
||||
materials=[
|
||||
# Hysteretic envelope (illustrative values for a W12x40 column):
|
||||
# My ≈ 150 kN·m at θy ≈ 0.01 rad;
|
||||
# M_ult ≈ 165 kN·m at θ_ult ≈ 0.05 rad.
|
||||
HystereticMaterial(
|
||||
id=1, name="HingeSteel",
|
||||
s1p=50e3, e1p=0.002,
|
||||
s2p=150e3, e2p=0.01,
|
||||
s3p=165e3, e3p=0.05,
|
||||
s1n=-50e3, e1n=-0.002,
|
||||
s2n=-150e3, e2n=-0.01,
|
||||
s3n=-165e3, e3n=-0.05,
|
||||
),
|
||||
],
|
||||
sections=[
|
||||
ElasticSection(
|
||||
id=1, name="W12x40",
|
||||
E=200e9, A=0.0076,
|
||||
Iz=2.0e-4, Iy=4.5e-5,
|
||||
G=80e9, J=8.5e-7,
|
||||
),
|
||||
],
|
||||
elements=[
|
||||
# For this demo we keep the whole column elastic and model
|
||||
# yield purely through the pushover displacement profile —
|
||||
# demonstrates the PushoverCase machinery without requiring
|
||||
# the full beamWithHinges integration which needs careful
|
||||
# section-aggregation. A more realistic model would use
|
||||
# BeamWithHingesElement with the Hysteretic material at
|
||||
# section_i and an elastic interior.
|
||||
ElasticBeamColumn(id=1, name="Col", nodes=(1, 2), section_id=1),
|
||||
],
|
||||
time_series=[LinearTimeSeries(id=1, name="Ramp")],
|
||||
load_patterns=[
|
||||
# Unit reference load at the top — the DisplacementControl
|
||||
# integrator doesn't need the magnitude to be correct, it
|
||||
# just scales it. OpenSees still needs SOME pattern loaded.
|
||||
PlainLoadPattern(
|
||||
id=1, name="PushRef",
|
||||
time_series_id=1,
|
||||
nodal_loads=[NodalLoad(node_id=2,
|
||||
forces=(1.0, 0, 0, 0, 0, 0))],
|
||||
),
|
||||
],
|
||||
analyses=[
|
||||
PushoverCase(
|
||||
id=1, name="Push-X",
|
||||
pattern_ids=[1],
|
||||
control_node=2, control_dof=1,
|
||||
target_disp=0.1, step_size=0.001,
|
||||
base_nodes=[1],
|
||||
),
|
||||
ModalCase(id=2, name="Modal-3", n_modes=3),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
project = build_sdof()
|
||||
project.validate_references()
|
||||
print(f"Built '{project.meta.name}' — {len(project.nodes)} nodes, "
|
||||
f"{len(project.elements)} elements, {len(project.analyses)} cases.")
|
||||
out_path = Path(__file__).with_suffix(".osmodel")
|
||||
save_project(project, out_path)
|
||||
print(f"Saved -> {out_path}")
|
||||
restored = load_project(out_path)
|
||||
restored.validate_references()
|
||||
assert restored.model_dump(by_alias=True) == project.model_dump(by_alias=True)
|
||||
print("Round-trip OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue