Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/openstaad_mcp/staad_skills/staad-analysis/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@ See [run-analysis.py](./scripts/run-analysis.py) for a complete working example.
- Wrap `AnalyzeModel`/`AnalyzeEx` in `SetSilentMode(True/False)` to prevent blocking dialogs
- For design workflows always use `AnalyzeEx(1, 0, 1)` — never `AnalyzeModel`
- `AnalyzeEx` runs both analysis AND design; `AnalyzeModel` runs analysis only
- **Compression-only springs/supports (elastic mat, plate mat with `springType=1`) are incompatible with P-Delta, Nonlinear, Buckling, and Cable analysis** — the engine uses member/spring deactivation iterations that cannot coexist with geometric nonlinearity or those other solver loops. The engine will throw an error. Use plain `PerformAnalysis` + `AnalyzeEx` for models with compression-only supports.
7 changes: 6 additions & 1 deletion src/openstaad_mcp/staad_skills/staad-geometry/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ description: 'Use when creating, querying, modifying, or selecting structure geo
- `geo.AddNode(x, y, z)` → node ID (coordinates in base unit)
- `geo.AddBeam(startNode, endNode)` → beam ID
- `geo.AddPlate(n1, n2, n3, n4)` → plate ID — pass **4 separate int args**, NOT a list
- **Triangle:** the API always takes 4 args; pass `0` as a sentinel for the missing 4th node → `geo.AddPlate(n1, n2, n3, 0)`
- `geo.AddSolid(n1, n2, n3, n4, n5, n6, n7, n8)` → solid ID

### Bulk Creation (more efficient than loops)
- `geo.AddMultipleNodes([[x,y,z], ...])` → list of node IDs
- `geo.AddMultipleBeams([[start,end], ...])` → list of beam IDs
- `geo.AddMultiplePlates([[n1,n2,n3,n4], ...])` → list of plate IDs
- **Triangle rows:** each row must have exactly 4 ints; use `0` as the sentinel 4th element → `[n1, n2, n3, 0]`

### Explicit ID Creation
- `geo.CreateNode(nodeNo, x, y, z)` — creates node with a specific ID
- `geo.CreateBeam(beamNo, startNode, endNode)` — beam with specific ID
- `geo.CreatePlate(plateNo, nA, nB, nC, nD)` — plate with specific ID (nD=0 for triangle)
- `geo.CreatePlate(plateNo, nA, nB, nC, nD)` — plate with specific ID
- **Triangle:** pass `0` for `nD` (the sentinel for a missing 4th node) → `geo.CreatePlate(id, nA, nB, nC, 0)`
- `geo.CreateSolid(solidNo, nA, nB, nC, nD, nE, nF, nG, nH)` — solid with specific ID

### Shared Element ID Sequence
Expand Down Expand Up @@ -128,9 +131,11 @@ pm_count = geo.GetPhysicalMemberCount()
## Examples
- [portal-frame.py](./scripts/portal-frame.py) — create a simple portal frame with supports
- [add-beam.py](./scripts/add-beam.py) — add a single beam between two new nodes
- [add-plate.py](./scripts/add-plate.py) — create quad and triangular plates (shows the `0` triangle convention)
- [select-members.py](./scripts/select-members.py) — select single and multiple beams

## Gotchas
- **Triangle plates use `0` as a sentinel:** all plate functions always take exactly 4 node arguments; `0` tells STAAD the slot is empty (i.e., this is a 3-node element). See [add-plate.py](./scripts/add-plate.py) for a full example.
- `AddPlate` takes 4 separate int arguments, NOT a list — `geo.AddPlate(n1, n2, n3, n4)` not `geo.AddPlate([n1,n2,n3,n4])`
- After adding geometry in the same script, call `staad.SetSilentMode(True)` → `staad.SaveModel(True)` → `staad.SetSilentMode(False)` before assigning properties, supports, or loads — do NOT use `UpdateStructure()` (it discards unsaved in-memory geometry)
- Always use `geo` (OSGeometry) for selections — do NOT use `OSView.SelectByItemList`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# add-plate.py
# Demonstrates creating quad plates and triangular plates.
#
# TRIANGLE SENTINEL: all plate functions take exactly 4 node args.
# Pass 0 as the 4th arg to signal a 3-node (triangular) plate.
# geo.AddPlate(n1, n2, n3, 0) <- triangle
# geo.AddMultiplePlates([[n1,n2,n3,0]]) <- triangle row
# geo.CreatePlate(id, nA, nB, nC, 0) <- explicit-ID triangle

geo = staad.Geometry

# ── Quad plate (4 corners in a 1×1 square) ──────────────────────────────────
n1 = geo.AddNode(0, 0, 0)
n2 = geo.AddNode(1, 0, 0)
n3 = geo.AddNode(1, 1, 0)
n4 = geo.AddNode(0, 1, 0)

quad_id = geo.AddPlate(n1, n2, n3, n4)
print(f'Quad plate {quad_id}: nodes {n1},{n2},{n3},{n4}')

# ── Triangular plate (apex above the midpoint) ───────────────────────────────
n5 = geo.AddNode(0.5, 0, 1) # apex node

# 0 is the sentinel for the missing 4th node
tri_id = geo.AddPlate(n1, n2, n5, 0)
print(f'Triangle plate {tri_id}: nodes {n1},{n2},{n5} (4th arg = 0 sentinel)')

# ── Bulk creation mixing quads and triangles ─────────────────────────────────
# Each row has exactly 4 ints; 0 is the sentinel for triangle (no 4th node)
plate_data = [
[n1, n2, n3, n4], # quad
[n1, n2, n5, 0], # triangle (0 = sentinel, no 4th node)
[n2, n3, n5, 0], # triangle (0 = sentinel, no 4th node)
]
plate_ids = geo.AddMultiplePlates(plate_data)
print(f'Bulk plates: {plate_ids}')

# ── Explicit-ID creation (triangle) ──────────────────────────────────────────
# geo.CreatePlate(plateNo, nA, nB, nC, nD) — nD=0 is the sentinel for triangle
next_id = max(geo.GetPlateList()) + 1
geo.CreatePlate(next_id, n1, n3, n5, 0) # nD=0 → triangle sentinel
print(f'Explicit-ID triangle plate {next_id}')
12 changes: 9 additions & 3 deletions src/openstaad_mcp/staad_skills/staad-supports/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@ Spring support distributed over tributary area.
See **[SUPPORT_CODES.md — Direction Codes](./assets/SUPPORT_CODES.md)** for `direction` values and **[SUPPORT_CODES.md — Spring Types](./assets/SUPPORT_CODES.md)** for `springType`.

```python
# Typical case: springs in Y direction (STAAD adds X/Z fixity for stability)
mat_id = sup.CreateElasticMat(
direction=5, # Y Only — compression only in Y
direction=1, # 1=Y Direction (use for most foundations)
subgrade=20.0, # kN/m^3 or equivalent
printFlag=0,
springType=1 # 1=Compression only
springType=0 # 0=Normal (bi-directional); 1=Compression only
)
sup.AssignSupportToEntityList(mat_id, [41, 42, 43])

# Y Only (direction=4): springs act ONLY in Y — use only when the model already
# has other supports (e.g. pinned/fixed nodes) providing X and Z restraint.
# Without those, the structure will be unstable in X/Z.
```

### Plate Mat Support
Expand Down Expand Up @@ -89,7 +94,7 @@ foot_id = sup.CreateElasticFooting(length, width, direction, subgrade)
| --------------------------------- | ------------------------------------------------- |
| `GetSupportCount()` | total supports |
| `GetSupportNodes()` | list of supported node IDs |
| `GetSupportType(nodeNo)` | support type code |
| `GetSupportType(nodeNo)` | support type code (see SUPPORT_CODES.md) |
| `GetSupportInformation(nodeNo)` | `(type, releases, springs)` |
| `GetSupportInformationEx(nodeNo)` | `(supportNo, type, releases, springs)` |
| `GetSupportName(supportNo)` | support name |
Expand All @@ -114,3 +119,4 @@ See [assign-fixed-supports.py](./scripts/assign-fixed-supports.py) for a complet
- `AssignSupportToNode` takes a SINGLE node ID — it does NOT accept a list; iterate with a loop
- When nodes were added in-memory in the same script, call `SaveModel(True)` before assigning supports — do NOT use `UpdateStructure()` (it discards unsaved geometry)
- For `CreateSupportFixedBut`: use `-1` for spring DOFs (not `1`); `1` = released, `0` = fixed, `-1` = spring
- **Compression-only supports (`springType=1`) are only compatible with plain linear static analysis** — using them with P-Delta, Nonlinear, Buckling, or Cable analysis causes an engine error. The engine uses spring deactivation iterations that cannot coexist with those solver modes.
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,37 @@

Used in `CreateElasticMat()`, `CreatePlateMat()`, `GetElasticMatDetail()`.

| Value | Direction |
| ----- | ---------------------------------------- |
| 0 | X Direction |
| 1 | Y Direction |
| 2 | Z Direction |
| 3 | X Only Direction (compression only in X) |
| 4 | Y Only Direction (compression only in Y) |
| 5 | Z Only Direction (compression only in Z) |
| 6 | All Directions (plate mat only) |
| Value | Direction |
| ----- | -------------------------------------------------------------------------------------- |
| 0 | X Direction |
| 1 | Y Direction *(typical for soil springs — use for most foundations)* |
| 2 | Z Direction |
| 3 | X Only — springs act in X only; model needs other supports for Y/Z stability |
| 4 | Y Only — springs act in Y only; model needs other supports for X/Z stability |
| 5 | Z Only — springs act in Z only; model needs other supports for X/Y stability |
| 6 | All Directions (plate mat only) |

## GetSupportType Return Codes

Returned by `GetSupportType(nodeNo)` and embedded in `GetSupportInformation` / `GetSupportInformationEx`.

| Value | Type |
| ----- | --------------------------------- |
| 0 | No support |
| 1 | Pinned |
| 2 | Fixed |
| 3 | Fixed with releases (FixedBut) |
| 4 | Enforced displacement |
| 5 | Enforced with releases |
| 6 | Inclined support |
| 7 | Elastic footing |
| 8 | Elastic mat |
| 9 | Plate mat |
| 10 | Multi-linear spring |
| 11 | Generated pinned |
| 12 | Generated fixed |
| 13 | Generated fixed with releases |
| -1 | Error |

## Spring Types

Expand Down
Loading