@theerapat-s28/ts-structural-eng-tools 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -1
- package/README.md +293 -131
- package/dist/core/constants/frame.constant.d.ts +8 -0
- package/dist/core/constants/frame.constant.js +9 -1
- package/dist/core/constants/frame.constant.js.map +1 -1
- package/dist/core/errors/fea.error.d.ts +47 -0
- package/dist/{esm/core/errors/frame-analysis.error.js → core/errors/fea.error.js} +14 -5
- package/dist/core/errors/fea.error.js.map +1 -0
- package/dist/core/index.d.ts +5 -3
- package/dist/core/index.js +10 -4
- package/dist/core/index.js.map +1 -1
- package/dist/esm/core/constants/frame.constant.js +8 -0
- package/dist/esm/core/constants/frame.constant.js.map +1 -1
- package/dist/{core/errors/frame-analysis.error.js → esm/core/errors/fea.error.js} +10 -9
- package/dist/esm/core/errors/fea.error.js.map +1 -0
- package/dist/esm/core/index.js +4 -2
- package/dist/esm/core/index.js.map +1 -1
- package/dist/esm/fea/analysis/index.js +7 -0
- package/dist/esm/fea/analysis/index.js.map +1 -0
- package/dist/esm/fea/{frame → analysis}/mesh/expand-model.js +30 -41
- package/dist/esm/fea/analysis/mesh/expand-model.js.map +1 -0
- package/dist/esm/fea/analysis/mesh/member-connectivity.js +66 -0
- package/dist/esm/fea/analysis/mesh/member-connectivity.js.map +1 -0
- package/dist/esm/fea/{frame → analysis}/post/demand-envelope.js +4 -4
- package/dist/esm/fea/analysis/post/demand-envelope.js.map +1 -0
- package/dist/esm/fea/analysis/post/envelope.js.map +1 -0
- package/dist/esm/fea/{frame → analysis}/post/present-state.js +6 -6
- package/dist/esm/fea/analysis/post/present-state.js.map +1 -0
- package/dist/esm/fea/{frame/solver/frame-system.js → analysis/solver/analysis-system.js} +17 -90
- package/dist/esm/fea/analysis/solver/analysis-system.js.map +1 -0
- package/dist/esm/fea/{frame/solver/analyze-frame.js → analysis/solver/analyze.js} +28 -18
- package/dist/esm/fea/analysis/solver/analyze.js.map +1 -0
- package/dist/esm/fea/{frame → analysis}/solver/combinations.js +8 -8
- package/dist/esm/fea/analysis/solver/combinations.js.map +1 -0
- package/dist/esm/fea/analysis/solver/distribute-area-loads.js +25 -0
- package/dist/esm/fea/analysis/solver/distribute-area-loads.js.map +1 -0
- package/dist/esm/fea/analysis/solver/load-case-solver.js +103 -0
- package/dist/esm/fea/analysis/solver/load-case-solver.js.map +1 -0
- package/dist/esm/fea/analysis/types/model.type.js +2 -0
- package/dist/esm/fea/analysis/types/model.type.js.map +1 -0
- package/dist/esm/fea/analysis/types/results.type.js +2 -0
- package/dist/esm/fea/analysis/types/results.type.js.map +1 -0
- package/dist/esm/fea/analysis/validation/validate-model.js +263 -0
- package/dist/esm/fea/analysis/validation/validate-model.js.map +1 -0
- package/dist/esm/fea/deprecated.js +9 -0
- package/dist/esm/fea/deprecated.js.map +1 -0
- package/dist/esm/fea/frame/area/{distribute-area-loads.js → area-member-loads.js} +7 -28
- package/dist/esm/fea/frame/area/area-member-loads.js.map +1 -0
- package/dist/esm/fea/frame/area/edge-members.js.map +1 -1
- package/dist/esm/fea/frame/elements/end-releases.js +2 -6
- package/dist/esm/fea/frame/elements/end-releases.js.map +1 -1
- package/dist/esm/fea/frame/elements/fixed-end-forces.js +5 -5
- package/dist/esm/fea/frame/elements/fixed-end-forces.js.map +1 -1
- package/dist/esm/fea/frame/elements/static-condensation.js +3 -3
- package/dist/esm/fea/frame/elements/static-condensation.js.map +1 -1
- package/dist/esm/fea/frame/index.js +1 -4
- package/dist/esm/fea/frame/index.js.map +1 -1
- package/dist/esm/fea/frame/post/member-diagram.js +4 -4
- package/dist/esm/fea/frame/post/member-diagram.js.map +1 -1
- package/dist/esm/fea/frame/solver/{global-assembly.js → member-assembly.js} +2 -10
- package/dist/esm/fea/frame/solver/member-assembly.js.map +1 -0
- package/dist/esm/fea/frame/solver/member-loads.js +141 -0
- package/dist/esm/fea/frame/solver/member-loads.js.map +1 -0
- package/dist/esm/fea/frame/solver/nodes-along-members.js +73 -0
- package/dist/esm/fea/frame/solver/nodes-along-members.js.map +1 -0
- package/dist/esm/fea/frame/solver/system-member.js +66 -0
- package/dist/esm/fea/frame/solver/system-member.js.map +1 -0
- package/dist/esm/fea/frame/transformation/coordinate-transform.js +3 -3
- package/dist/esm/fea/frame/transformation/coordinate-transform.js.map +1 -1
- package/dist/esm/fea/frame/validation/validate-members.js +164 -0
- package/dist/esm/fea/frame/validation/validate-members.js.map +1 -0
- package/dist/esm/fea/frame/validation/validate-null-areas.js +88 -0
- package/dist/esm/fea/frame/validation/validate-null-areas.js.map +1 -0
- package/dist/esm/fea/index.js +4 -1
- package/dist/esm/fea/index.js.map +1 -1
- package/dist/esm/fea/shared/index.js +2 -0
- package/dist/esm/fea/shared/index.js.map +1 -0
- package/dist/esm/fea/shared/solver/auto-restraint.js.map +1 -0
- package/dist/esm/fea/{frame → shared}/solver/boundary-conditions.js +5 -1
- package/dist/esm/fea/shared/solver/boundary-conditions.js.map +1 -0
- package/dist/esm/fea/shared/solver/global-assembly.js +10 -0
- package/dist/esm/fea/shared/solver/global-assembly.js.map +1 -0
- package/dist/esm/fea/shared/types/model.type.js +2 -0
- package/dist/esm/fea/shared/types/model.type.js.map +1 -0
- package/dist/esm/fea/shared/validation/issues.js +32 -0
- package/dist/esm/fea/shared/validation/issues.js.map +1 -0
- package/dist/esm/fea/{frame/elements/shell → shell/elements}/dkq-plate.js +1 -1
- package/dist/esm/fea/shell/elements/dkq-plate.js.map +1 -0
- package/dist/esm/fea/{frame/elements/shell → shell/elements}/flat-shell.js +1 -1
- package/dist/esm/fea/shell/elements/flat-shell.js.map +1 -0
- package/dist/esm/fea/{frame/elements/shell → shell/elements}/membrane-quad.js +2 -2
- package/dist/esm/fea/shell/elements/membrane-quad.js.map +1 -0
- package/dist/esm/fea/shell/elements/quad-geometry.js.map +1 -0
- package/dist/esm/fea/shell/elements/rigidity.js.map +1 -0
- package/dist/esm/fea/{frame/elements/shell → shell/elements}/shell-axes.js +1 -1
- package/dist/esm/fea/shell/elements/shell-axes.js.map +1 -0
- package/dist/esm/fea/shell/index.js +2 -0
- package/dist/esm/fea/shell/index.js.map +1 -0
- package/dist/esm/fea/{frame → shell}/mesh/mesh-shells.js +1 -1
- package/dist/esm/fea/shell/mesh/mesh-shells.js.map +1 -0
- package/dist/esm/fea/{frame → shell}/post/shell-forces.js +4 -4
- package/dist/esm/fea/{frame → shell}/post/shell-forces.js.map +1 -1
- package/dist/esm/fea/shell/solver/shell-loads.js +53 -0
- package/dist/esm/fea/shell/solver/shell-loads.js.map +1 -0
- package/dist/esm/fea/shell/solver/system-shell.js +37 -0
- package/dist/esm/fea/shell/solver/system-shell.js.map +1 -0
- package/dist/esm/fea/shell/types/model.type.js +2 -0
- package/dist/esm/fea/shell/types/model.type.js.map +1 -0
- package/dist/esm/fea/shell/types/results.type.js +2 -0
- package/dist/esm/fea/shell/types/results.type.js.map +1 -0
- package/dist/esm/fea/shell/validation/validate-shells.js +98 -0
- package/dist/esm/fea/shell/validation/validate-shells.js.map +1 -0
- package/dist/esm/index.js +5 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/fea/analysis/index.d.ts +10 -0
- package/dist/fea/analysis/index.js +16 -0
- package/dist/fea/analysis/index.js.map +1 -0
- package/dist/fea/analysis/mesh/expand-model.d.ts +34 -0
- package/dist/fea/{frame → analysis}/mesh/expand-model.js +30 -41
- package/dist/fea/analysis/mesh/expand-model.js.map +1 -0
- package/dist/fea/analysis/mesh/member-connectivity.d.ts +43 -0
- package/dist/fea/analysis/mesh/member-connectivity.js +71 -0
- package/dist/fea/analysis/mesh/member-connectivity.js.map +1 -0
- package/dist/fea/{frame → analysis}/post/demand-envelope.d.ts +5 -5
- package/dist/fea/{frame → analysis}/post/demand-envelope.js +4 -4
- package/dist/fea/analysis/post/demand-envelope.js.map +1 -0
- package/dist/fea/{frame → analysis}/post/envelope.d.ts +2 -2
- package/dist/fea/analysis/post/envelope.js.map +1 -0
- package/dist/fea/analysis/post/present-state.d.ts +21 -0
- package/dist/fea/{frame → analysis}/post/present-state.js +7 -7
- package/dist/fea/analysis/post/present-state.js.map +1 -0
- package/dist/fea/analysis/solver/analysis-system.d.ts +46 -0
- package/dist/fea/{frame/solver/frame-system.js → analysis/solver/analysis-system.js} +22 -95
- package/dist/fea/analysis/solver/analysis-system.js.map +1 -0
- package/dist/fea/{frame/solver/analyze-frame.d.ts → analysis/solver/analyze.d.ts} +29 -20
- package/dist/fea/{frame/solver/analyze-frame.js → analysis/solver/analyze.js} +33 -23
- package/dist/fea/analysis/solver/analyze.js.map +1 -0
- package/dist/fea/{frame → analysis}/solver/combinations.d.ts +1 -1
- package/dist/fea/{frame → analysis}/solver/combinations.js +8 -8
- package/dist/fea/analysis/solver/combinations.js.map +1 -0
- package/dist/fea/{frame/area → analysis/solver}/distribute-area-loads.d.ts +6 -15
- package/dist/fea/analysis/solver/distribute-area-loads.js +29 -0
- package/dist/fea/analysis/solver/distribute-area-loads.js.map +1 -0
- package/dist/fea/{frame → analysis}/solver/load-case-solver.d.ts +9 -13
- package/dist/fea/analysis/solver/load-case-solver.js +108 -0
- package/dist/fea/analysis/solver/load-case-solver.js.map +1 -0
- package/dist/fea/analysis/types/model.type.d.ts +80 -0
- package/dist/fea/analysis/types/model.type.js +3 -0
- package/dist/fea/analysis/types/model.type.js.map +1 -0
- package/dist/fea/analysis/types/results.type.d.ts +123 -0
- package/dist/fea/analysis/types/results.type.js +3 -0
- package/dist/fea/analysis/types/results.type.js.map +1 -0
- package/dist/fea/analysis/validation/validate-model.d.ts +12 -0
- package/dist/fea/analysis/validation/validate-model.js +267 -0
- package/dist/fea/analysis/validation/validate-model.js.map +1 -0
- package/dist/fea/deprecated.d.ts +27 -0
- package/dist/fea/deprecated.js +12 -0
- package/dist/fea/deprecated.js.map +1 -0
- package/dist/fea/frame/area/area-member-loads.d.ts +19 -0
- package/dist/fea/frame/area/{distribute-area-loads.js → area-member-loads.js} +8 -30
- package/dist/fea/frame/area/area-member-loads.js.map +1 -0
- package/dist/fea/frame/area/edge-members.d.ts +5 -4
- package/dist/fea/frame/area/edge-members.js.map +1 -1
- package/dist/fea/frame/elements/end-releases.d.ts +1 -6
- package/dist/fea/frame/elements/end-releases.js +4 -8
- package/dist/fea/frame/elements/end-releases.js.map +1 -1
- package/dist/fea/frame/elements/fixed-end-forces.d.ts +1 -1
- package/dist/fea/frame/elements/fixed-end-forces.js +5 -5
- package/dist/fea/frame/elements/fixed-end-forces.js.map +1 -1
- package/dist/fea/frame/elements/static-condensation.d.ts +1 -1
- package/dist/fea/frame/elements/static-condensation.js +3 -3
- package/dist/fea/frame/elements/static-condensation.js.map +1 -1
- package/dist/fea/frame/index.d.ts +2 -8
- package/dist/fea/frame/index.js +2 -10
- package/dist/fea/frame/index.js.map +1 -1
- package/dist/fea/frame/post/member-diagram.d.ts +8 -8
- package/dist/fea/frame/post/member-diagram.js +4 -4
- package/dist/fea/frame/post/member-diagram.js.map +1 -1
- package/dist/fea/frame/solver/{global-assembly.d.ts → member-assembly.d.ts} +0 -11
- package/dist/fea/frame/solver/{global-assembly.js → member-assembly.js} +4 -13
- package/dist/fea/frame/solver/member-assembly.js.map +1 -0
- package/dist/fea/frame/solver/member-loads.d.ts +21 -0
- package/dist/fea/frame/solver/member-loads.js +146 -0
- package/dist/fea/frame/solver/member-loads.js.map +1 -0
- package/dist/fea/frame/solver/nodes-along-members.d.ts +31 -0
- package/dist/fea/frame/solver/nodes-along-members.js +77 -0
- package/dist/fea/frame/solver/nodes-along-members.js.map +1 -0
- package/dist/fea/frame/solver/system-member.d.ts +51 -0
- package/dist/fea/frame/solver/system-member.js +70 -0
- package/dist/fea/frame/solver/system-member.js.map +1 -0
- package/dist/fea/frame/transformation/coordinate-transform.d.ts +1 -1
- package/dist/fea/frame/transformation/coordinate-transform.js +3 -3
- package/dist/fea/frame/transformation/coordinate-transform.js.map +1 -1
- package/dist/fea/frame/types/model.type.d.ts +16 -175
- package/dist/fea/frame/types/results.type.d.ts +17 -152
- package/dist/fea/frame/validation/validate-members.d.ts +30 -0
- package/dist/fea/frame/validation/validate-members.js +169 -0
- package/dist/fea/frame/validation/validate-members.js.map +1 -0
- package/dist/fea/frame/validation/validate-null-areas.d.ts +38 -0
- package/dist/fea/frame/validation/validate-null-areas.js +93 -0
- package/dist/fea/frame/validation/validate-null-areas.js.map +1 -0
- package/dist/fea/index.d.ts +4 -0
- package/dist/fea/index.js +4 -1
- package/dist/fea/index.js.map +1 -1
- package/dist/fea/shared/index.d.ts +1 -0
- package/dist/fea/shared/index.js +3 -0
- package/dist/fea/shared/index.js.map +1 -0
- package/dist/fea/shared/solver/auto-restraint.js.map +1 -0
- package/dist/fea/{frame → shared}/solver/boundary-conditions.d.ts +5 -0
- package/dist/fea/{frame → shared}/solver/boundary-conditions.js +7 -3
- package/dist/fea/shared/solver/boundary-conditions.js.map +1 -0
- package/dist/fea/shared/solver/global-assembly.d.ts +12 -0
- package/dist/fea/shared/solver/global-assembly.js +14 -0
- package/dist/fea/shared/solver/global-assembly.js.map +1 -0
- package/dist/fea/shared/types/model.type.d.ts +34 -0
- package/dist/fea/shared/types/model.type.js +3 -0
- package/dist/fea/shared/types/model.type.js.map +1 -0
- package/dist/fea/shared/validation/issues.d.ts +9 -0
- package/dist/fea/shared/validation/issues.js +38 -0
- package/dist/fea/shared/validation/issues.js.map +1 -0
- package/dist/fea/{frame/elements/shell → shell/elements}/dkq-plate.d.ts +1 -1
- package/dist/fea/{frame/elements/shell → shell/elements}/dkq-plate.js +1 -1
- package/dist/fea/shell/elements/dkq-plate.js.map +1 -0
- package/dist/fea/{frame/elements/shell → shell/elements}/flat-shell.d.ts +1 -1
- package/dist/fea/{frame/elements/shell → shell/elements}/flat-shell.js +1 -1
- package/dist/fea/shell/elements/flat-shell.js.map +1 -0
- package/dist/fea/{frame/elements/shell → shell/elements}/membrane-quad.d.ts +1 -1
- package/dist/fea/{frame/elements/shell → shell/elements}/membrane-quad.js +2 -2
- package/dist/fea/shell/elements/membrane-quad.js.map +1 -0
- package/dist/fea/shell/elements/quad-geometry.js.map +1 -0
- package/dist/fea/{frame/elements/shell → shell/elements}/rigidity.d.ts +1 -1
- package/dist/fea/shell/elements/rigidity.js.map +1 -0
- package/dist/fea/{frame/elements/shell → shell/elements}/shell-axes.d.ts +1 -1
- package/dist/fea/{frame/elements/shell → shell/elements}/shell-axes.js +1 -1
- package/dist/fea/shell/elements/shell-axes.js.map +1 -0
- package/dist/fea/shell/index.d.ts +2 -0
- package/dist/fea/shell/index.js +3 -0
- package/dist/fea/shell/index.js.map +1 -0
- package/dist/fea/{frame → shell}/mesh/mesh-shells.d.ts +7 -6
- package/dist/fea/{frame → shell}/mesh/mesh-shells.js +1 -1
- package/dist/fea/shell/mesh/mesh-shells.js.map +1 -0
- package/dist/fea/{frame → shell}/post/shell-forces.d.ts +1 -1
- package/dist/fea/{frame → shell}/post/shell-forces.js +4 -4
- package/dist/fea/{frame → shell}/post/shell-forces.js.map +1 -1
- package/dist/fea/shell/solver/shell-loads.d.ts +17 -0
- package/dist/fea/shell/solver/shell-loads.js +57 -0
- package/dist/fea/shell/solver/shell-loads.js.map +1 -0
- package/dist/fea/shell/solver/system-shell.d.ts +29 -0
- package/dist/fea/shell/solver/system-shell.js +41 -0
- package/dist/fea/shell/solver/system-shell.js.map +1 -0
- package/dist/fea/shell/types/model.type.d.ts +57 -0
- package/dist/fea/shell/types/model.type.js +3 -0
- package/dist/fea/shell/types/model.type.js.map +1 -0
- package/dist/fea/shell/types/results.type.d.ts +47 -0
- package/dist/fea/shell/types/results.type.js +3 -0
- package/dist/fea/shell/types/results.type.js.map +1 -0
- package/dist/fea/shell/validation/validate-shells.d.ts +21 -0
- package/dist/fea/shell/validation/validate-shells.js +103 -0
- package/dist/fea/shell/validation/validate-shells.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +16 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/core/errors/frame-analysis.error.d.ts +0 -37
- package/dist/core/errors/frame-analysis.error.js.map +0 -1
- package/dist/esm/core/errors/frame-analysis.error.js.map +0 -1
- package/dist/esm/fea/frame/area/distribute-area-loads.js.map +0 -1
- package/dist/esm/fea/frame/elements/shell/dkq-plate.js.map +0 -1
- package/dist/esm/fea/frame/elements/shell/flat-shell.js.map +0 -1
- package/dist/esm/fea/frame/elements/shell/membrane-quad.js.map +0 -1
- package/dist/esm/fea/frame/elements/shell/quad-geometry.js.map +0 -1
- package/dist/esm/fea/frame/elements/shell/rigidity.js.map +0 -1
- package/dist/esm/fea/frame/elements/shell/shell-axes.js.map +0 -1
- package/dist/esm/fea/frame/mesh/expand-model.js.map +0 -1
- package/dist/esm/fea/frame/mesh/mesh-shells.js.map +0 -1
- package/dist/esm/fea/frame/post/demand-envelope.js.map +0 -1
- package/dist/esm/fea/frame/post/envelope.js.map +0 -1
- package/dist/esm/fea/frame/post/present-state.js.map +0 -1
- package/dist/esm/fea/frame/solver/analyze-frame.js.map +0 -1
- package/dist/esm/fea/frame/solver/auto-restraint.js.map +0 -1
- package/dist/esm/fea/frame/solver/boundary-conditions.js.map +0 -1
- package/dist/esm/fea/frame/solver/combinations.js.map +0 -1
- package/dist/esm/fea/frame/solver/frame-system.js.map +0 -1
- package/dist/esm/fea/frame/solver/global-assembly.js.map +0 -1
- package/dist/esm/fea/frame/solver/load-case-solver.js +0 -255
- package/dist/esm/fea/frame/solver/load-case-solver.js.map +0 -1
- package/dist/esm/fea/frame/validation/validate-model.js +0 -529
- package/dist/esm/fea/frame/validation/validate-model.js.map +0 -1
- package/dist/fea/frame/area/distribute-area-loads.js.map +0 -1
- package/dist/fea/frame/elements/shell/dkq-plate.js.map +0 -1
- package/dist/fea/frame/elements/shell/flat-shell.js.map +0 -1
- package/dist/fea/frame/elements/shell/membrane-quad.js.map +0 -1
- package/dist/fea/frame/elements/shell/quad-geometry.js.map +0 -1
- package/dist/fea/frame/elements/shell/rigidity.js.map +0 -1
- package/dist/fea/frame/elements/shell/shell-axes.js.map +0 -1
- package/dist/fea/frame/mesh/expand-model.d.ts +0 -29
- package/dist/fea/frame/mesh/expand-model.js.map +0 -1
- package/dist/fea/frame/mesh/mesh-shells.js.map +0 -1
- package/dist/fea/frame/post/demand-envelope.js.map +0 -1
- package/dist/fea/frame/post/envelope.js.map +0 -1
- package/dist/fea/frame/post/present-state.d.ts +0 -20
- package/dist/fea/frame/post/present-state.js.map +0 -1
- package/dist/fea/frame/solver/analyze-frame.js.map +0 -1
- package/dist/fea/frame/solver/auto-restraint.js.map +0 -1
- package/dist/fea/frame/solver/boundary-conditions.js.map +0 -1
- package/dist/fea/frame/solver/combinations.js.map +0 -1
- package/dist/fea/frame/solver/frame-system.d.ts +0 -89
- package/dist/fea/frame/solver/frame-system.js.map +0 -1
- package/dist/fea/frame/solver/global-assembly.js.map +0 -1
- package/dist/fea/frame/solver/load-case-solver.js +0 -260
- package/dist/fea/frame/solver/load-case-solver.js.map +0 -1
- package/dist/fea/frame/validation/validate-model.d.ts +0 -19
- package/dist/fea/frame/validation/validate-model.js +0 -535
- package/dist/fea/frame/validation/validate-model.js.map +0 -1
- /package/dist/esm/fea/{frame → analysis}/post/envelope.js +0 -0
- /package/dist/esm/fea/{frame → shared}/solver/auto-restraint.js +0 -0
- /package/dist/esm/fea/{frame/elements/shell → shell/elements}/quad-geometry.js +0 -0
- /package/dist/esm/fea/{frame/elements/shell → shell/elements}/rigidity.js +0 -0
- /package/dist/fea/{frame → analysis}/post/envelope.js +0 -0
- /package/dist/fea/{frame → shared}/solver/auto-restraint.d.ts +0 -0
- /package/dist/fea/{frame → shared}/solver/auto-restraint.js +0 -0
- /package/dist/fea/{frame/elements/shell → shell/elements}/quad-geometry.d.ts +0 -0
- /package/dist/fea/{frame/elements/shell → shell/elements}/quad-geometry.js +0 -0
- /package/dist/fea/{frame/elements/shell → shell/elements}/rigidity.js +0 -0
package/README.md
CHANGED
|
@@ -1,72 +1,61 @@
|
|
|
1
1
|
# ts-structural-eng
|
|
2
2
|
|
|
3
|
-
**📖 [API Reference — theerapat-s28.github.io/ts-structural-eng](https://theerapat-s28.github.io/ts-structural-eng/)**
|
|
3
|
+
**📖 [API Reference — theerapat-s28.github.io/ts-structural-eng](https://theerapat-s28.github.io/ts-structural-eng/)** · [npm](https://www.npmjs.com/package/@theerapat-s28/ts-structural-eng-tools) · [Changelog](CHANGELOG.md)
|
|
4
4
|
|
|
5
|
-
A headless structural analysis and design engine for TypeScript: 3D
|
|
5
|
+
A headless structural analysis and design engine for TypeScript: 3D analysis of frames and shells — beams, columns, braces, walls, slabs and cores — by the direct stiffness method, reinforced-concrete beam design per ACI 318-19, and strengthening methods. It is built to be installed by front-end applications as their calculation core.
|
|
6
6
|
|
|
7
7
|
## Scope: an engine, not an application
|
|
8
8
|
|
|
9
9
|
The library does the structural engineering and nothing else. A front-end application installs it, builds a model from its own UI, calls the engine, and draws the results.
|
|
10
10
|
|
|
11
|
-
| The engine (this package)
|
|
12
|
-
|
|
|
13
|
-
| Model validation with located errors (`details` name the node, member, field…) | Input forms, drawing tools, highlighting the reported problems
|
|
14
|
-
| Analysis: load cases, combinations, envelopes, member diagrams
|
|
15
|
-
| Design checks with code-clause warnings and `RCDesignError` / `
|
|
16
|
-
| Typed inputs and results in SI units
|
|
11
|
+
| The engine (this package) | The front-end application |
|
|
12
|
+
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
13
|
+
| Model validation with located errors (`details` name the node, member, shell, field…) | Input forms, drawing tools, highlighting the reported problems |
|
|
14
|
+
| Analysis: load cases, combinations, envelopes, member diagrams, shell forces | Rendering the model, the mesh, deformed shapes, diagrams and contours |
|
|
15
|
+
| Design checks with code-clause warnings and `RCDesignError` / `FeaError` | Display of results, member colours, view and display options |
|
|
16
|
+
| Typed inputs and results in SI units | Unit display, project files, undo history, other UI state |
|
|
17
17
|
|
|
18
18
|
What this means in practice:
|
|
19
19
|
|
|
20
20
|
- **No UI, no rendering, no presentation data.** Inputs and results carry structural quantities only; no colours, labels or view state.
|
|
21
|
-
- **Plain JSON in, plain JSON out.** Models and results are serialisable, so the engine runs in a Web Worker, in the browser or in Node.
|
|
21
|
+
- **Plain JSON in, plain JSON out.** Models and results are serialisable, so the engine runs in a Web Worker, in the browser or in Node.js.
|
|
22
22
|
- **No runtime dependencies** and no DOM or Node-only APIs.
|
|
23
|
-
- **ESM and CommonJS builds** with `.d.ts` types, tree-shakeable (`"sideEffects": false`), split into subpath exports
|
|
23
|
+
- **ESM and CommonJS builds** with `.d.ts` types, tree-shakeable (`"sideEffects": false`), split into subpath exports.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @theerapat-s28/ts-structural-eng-tools
|
|
29
|
+
# or: npm install @theerapat-s28/ts-structural-eng-tools
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Import from a module's subpath — `/fea`, `/rc`, `/strengthening`, `/core` or `/utils` — so a front end loads only what it uses, or from the package root, which re-exports every function, type and constant of every module.
|
|
33
|
+
|
|
34
|
+
**Upgrading from 2.x?** Nothing was removed, frame-only models give the same results, and the exports renamed in 3.2.0 keep their old names as deprecated aliases. Results gain a few fields, and models with shells bring new error codes and generated mesh nodes; [Upgrading from 2.x](CHANGELOG.md#upgrading-from-2x) in the changelog lists what a front end may need to handle.
|
|
24
35
|
|
|
25
36
|
## Documentation
|
|
26
37
|
|
|
27
38
|
Full API reference, with parameter tables, worked examples, warnings and error codes:
|
|
28
39
|
|
|
29
40
|
- **[API reference](https://theerapat-s28.github.io/ts-structural-eng/)** — landing page
|
|
41
|
+
- [FEA — Frame and shell analysis](https://theerapat-s28.github.io/ts-structural-eng/fea/) — `@theerapat-s28/ts-structural-eng-tools/fea`
|
|
30
42
|
- [RC Beam Design](https://theerapat-s28.github.io/ts-structural-eng/rc/) — `@theerapat-s28/ts-structural-eng-tools/rc`
|
|
31
43
|
- [Strengthening](https://theerapat-s28.github.io/ts-structural-eng/strengthening/) — `@theerapat-s28/ts-structural-eng-tools/strengthening`
|
|
32
|
-
- [FEA — Frame Analysis](https://theerapat-s28.github.io/ts-structural-eng/fea/) — `@theerapat-s28/ts-structural-eng-tools/fea`
|
|
33
44
|
- [Shell element theory notes](https://theerapat-s28.github.io/ts-structural-eng/shell-element.html) — how the shell element's stiffness is formed, with its benchmarks
|
|
34
45
|
|
|
35
46
|
The pages are served from [`html-docs/`](https://github.com/theerapat-s28/ts-structural-eng/tree/main/html-docs) via GitHub Pages.
|
|
36
47
|
|
|
37
|
-
## Quick
|
|
38
|
-
|
|
39
|
-
- Package: `@theerapat-s28/ts-structural-eng-tools`
|
|
40
|
-
- Entry: `src/index.ts`
|
|
41
|
-
- Build output: `dist/` (CommonJS + `.d.ts` files) and `dist/esm/` (ES modules)
|
|
42
|
-
|
|
43
|
-
## Prerequisites
|
|
44
|
-
|
|
45
|
-
- Node.js (v18+ recommended)
|
|
46
|
-
- pnpm
|
|
47
|
-
|
|
48
|
-
## Install
|
|
49
|
-
|
|
50
|
-
Use the published package:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
pnpm add @theerapat-s28/ts-structural-eng-tools
|
|
54
|
-
# or: npm install @theerapat-s28/ts-structural-eng-tools
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Or install this repository's dependencies to work on the library itself:
|
|
48
|
+
## Quick start
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
pnpm install
|
|
61
|
-
```
|
|
50
|
+
Two models, one with members only and one that adds a slab as shell elements. The values in the comments are what the engine returns for these inputs.
|
|
62
51
|
|
|
63
|
-
|
|
52
|
+
### Frame only: an RC beam from analysis to design check
|
|
64
53
|
|
|
65
54
|
Analyse a simply supported RC beam under self-weight and live load, envelope the design demands, and check them against the section's flexural capacity:
|
|
66
55
|
|
|
67
56
|
```ts
|
|
68
|
-
import {
|
|
69
|
-
import type {
|
|
57
|
+
import { analyze, memberDemandEnvelope } from "@theerapat-s28/ts-structural-eng-tools/fea";
|
|
58
|
+
import type { FeaModel } from "@theerapat-s28/ts-structural-eng-tools/fea";
|
|
70
59
|
import {
|
|
71
60
|
rectBeamMomentCapacity,
|
|
72
61
|
rectBeamToSectionProperties,
|
|
@@ -76,7 +65,7 @@ import {
|
|
|
76
65
|
const beam = { Es: 200_000, fc_: 28, fy: 420, As: 1800, b: 300, h: 600, d: 540 };
|
|
77
66
|
const { sectionProperties } = rectBeamToSectionProperties(beam, { member: "beam" });
|
|
78
67
|
|
|
79
|
-
const model:
|
|
68
|
+
const model: FeaModel = {
|
|
80
69
|
nodes: [
|
|
81
70
|
{ id: "A", x: 0, y: 0, z: 0 },
|
|
82
71
|
{ id: "B", x: 6000, y: 0, z: 0 }, // mm
|
|
@@ -102,7 +91,13 @@ const model: FrameModel = {
|
|
|
102
91
|
],
|
|
103
92
|
};
|
|
104
93
|
|
|
105
|
-
const result =
|
|
94
|
+
const result = analyze(model);
|
|
95
|
+
|
|
96
|
+
// Diagrams along every member, ready for plotting
|
|
97
|
+
const { stations } = result.combinations["1.2D+1.6L"].memberDiagrams[0];
|
|
98
|
+
stations.find((s) => s.x === 3000); // M3 → 131.328 (kN·m), uz → -10.47731 (mm) at mid-span
|
|
99
|
+
|
|
100
|
+
// Design demands enveloped over the combinations, then the capacity check
|
|
106
101
|
const demand = memberDemandEnvelope(result, "AB");
|
|
107
102
|
// demand.MuPositive → 131.328 (kN·m), demand.Vu → 87.552 (kN), governed by "1.2D+1.6L"
|
|
108
103
|
|
|
@@ -110,22 +105,246 @@ const { phiMn, warnings } = rectBeamMomentCapacity(beam);
|
|
|
110
105
|
// phiMn → 331.39 (kN·m), warnings → []
|
|
111
106
|
```
|
|
112
107
|
|
|
113
|
-
|
|
108
|
+
`rectBeamToSectionProperties` gives the frame section of an RC rectangle with the ACI 318-19 6.6.3.1.1 cracked inertia (0.35 Ig for a beam) and a unit weight, so `selfWeight: 1` loads the beam with its own weight.
|
|
109
|
+
|
|
110
|
+
### Frame with shells: a slab on edge beams and columns
|
|
111
|
+
|
|
112
|
+
A 6 × 5 m, 200 mm slab on four edge beams and four columns. The slab is one shell area; the engine meshes it, splits the edge beams at the mesh nodes so they share them with the slab, and reports the slab's forces per element:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { analyze, memberDemandEnvelope } from "@theerapat-s28/ts-structural-eng-tools/fea";
|
|
116
|
+
import type { FeaModel } from "@theerapat-s28/ts-structural-eng-tools/fea";
|
|
117
|
+
import {
|
|
118
|
+
concreteElasticModulus,
|
|
119
|
+
rectBeamToSectionProperties,
|
|
120
|
+
} from "@theerapat-s28/ts-structural-eng-tools/rc";
|
|
121
|
+
|
|
122
|
+
const fc_ = 28; // MPa
|
|
123
|
+
const beam = rectBeamToSectionProperties({ fc_, b: 300, h: 600 }, { member: "beam" });
|
|
124
|
+
const column = rectBeamToSectionProperties({ fc_, b: 400, h: 400 }, { member: "column" });
|
|
125
|
+
const fixed = { ux: true, uy: true, uz: true, rx: true, ry: true, rz: true };
|
|
126
|
+
|
|
127
|
+
const model: FeaModel = {
|
|
128
|
+
nodes: [
|
|
129
|
+
{ id: "A", x: 0, y: 0, z: 3500 }, // slab corners, mm
|
|
130
|
+
{ id: "B", x: 6000, y: 0, z: 3500 },
|
|
131
|
+
{ id: "C", x: 6000, y: 5000, z: 3500 },
|
|
132
|
+
{ id: "D", x: 0, y: 5000, z: 3500 },
|
|
133
|
+
{ id: "A0", x: 0, y: 0, z: 0 }, // column bases
|
|
134
|
+
{ id: "B0", x: 6000, y: 0, z: 0 },
|
|
135
|
+
{ id: "C0", x: 6000, y: 5000, z: 0 },
|
|
136
|
+
{ id: "D0", x: 0, y: 5000, z: 0 },
|
|
137
|
+
],
|
|
138
|
+
members: [
|
|
139
|
+
...["A", "B", "C", "D"].map((id) => ({
|
|
140
|
+
id: `col${id}`,
|
|
141
|
+
startNodeId: `${id}0`,
|
|
142
|
+
endNodeId: id,
|
|
143
|
+
section: column.sectionProperties,
|
|
144
|
+
})),
|
|
145
|
+
{ id: "AB", startNodeId: "A", endNodeId: "B", section: beam.sectionProperties }, // edge beams
|
|
146
|
+
{ id: "BC", startNodeId: "B", endNodeId: "C", section: beam.sectionProperties },
|
|
147
|
+
{ id: "CD", startNodeId: "C", endNodeId: "D", section: beam.sectionProperties },
|
|
148
|
+
{ id: "DA", startNodeId: "D", endNodeId: "A", section: beam.sectionProperties },
|
|
149
|
+
],
|
|
150
|
+
restraints: ["A0", "B0", "C0", "D0"].map((nodeId) => ({ nodeId, ...fixed })),
|
|
151
|
+
shells: [
|
|
152
|
+
{
|
|
153
|
+
id: "slab",
|
|
154
|
+
nodeIds: ["A", "B", "C", "D"], // counter-clockwise seen from above, so local 3 = +Z
|
|
155
|
+
section: { thickness: 200, E: concreteElasticModulus(fc_), nu: 0.2, unitWeight: 24 },
|
|
156
|
+
mesh: { maxSize: 500 }, // the engine divides it into 12 × 10 elements
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
loadCases: [
|
|
160
|
+
{ id: "D", type: "dead", selfWeight: 1 },
|
|
161
|
+
{ id: "L", type: "live" },
|
|
162
|
+
],
|
|
163
|
+
areaLoads: [{ loadCase: "L", areaId: "slab", direction: "Z", q: -3 }], // kN/m²
|
|
164
|
+
combinations: [
|
|
165
|
+
{
|
|
166
|
+
id: "1.2D+1.6L",
|
|
167
|
+
terms: [
|
|
168
|
+
{ case: "D", factor: 1.2 },
|
|
169
|
+
{ case: "L", factor: 1.6 },
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const result = analyze(model);
|
|
176
|
+
const mesh = result.mesh!; // present whenever the model has shells
|
|
177
|
+
|
|
178
|
+
// Draw the mesh: 120 elements, each with its four corner nodes
|
|
179
|
+
const xyz = new Map([...model.nodes, ...mesh.nodes].map((n) => [n.id, n]));
|
|
180
|
+
const quads = mesh.shells.map((element) => element.nodeIds.map((id) => xyz.get(id)!));
|
|
181
|
+
// mesh.shells[0] → { id: "slab:0,0", areaId: "slab", nodeIds: ["A", "A~B:1", "slab:1,1", "A~D:1"] }
|
|
182
|
+
|
|
183
|
+
// Slab moments at the element corners, in the slab's local axes (local 1 = +X here)
|
|
184
|
+
const combo = result.combinations["1.2D+1.6L"];
|
|
185
|
+
const M11 = combo.shellForces.flatMap((element) => element.corners.map((c) => c.M11));
|
|
186
|
+
// Math.max(...M11) → 18.849 (kN·m/m), sagging at the slab centre
|
|
187
|
+
// Math.min(...M11) → -15.4157 (kN·m/m), hogging at the corners over the columns
|
|
188
|
+
|
|
189
|
+
// Node results include the generated nodes; "slab:6,5" is the slab centre
|
|
190
|
+
combo.nodalDisplacements.find((d) => d.nodeId === "slab:6,5"); // uz → -4.99265 (mm)
|
|
191
|
+
|
|
192
|
+
// The edge beams are split at the mesh nodes, but report under their own ids
|
|
193
|
+
memberDemandEnvelope(result, "AB"); // MuPositive → 45.8202, MuNegative → 37.2024 (kN·m), Vu → 56.5957 (kN)
|
|
194
|
+
|
|
195
|
+
combo.reactions.reduce((sum, r) => sum + r.fz, 0); // → 495.36 (kN), the total factored load
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
What changes for the front end when a model has shells:
|
|
199
|
+
|
|
200
|
+
- **Generated nodes.** `result.mesh.nodes` holds the nodes the engine generated, and `nodalDisplacements` and `reactions` list them after your own nodes. Their ids are strings even when yours are numbers: `"<areaId>:<i>,<j>"` inside an area, `"<a>~<b>:<k>"` along an edge between your nodes `a` and `b`.
|
|
201
|
+
- **Elements.** `result.mesh.shells` lists every element with its four nodes. `shellForces` and `envelope.shells` have one entry per element, named by `shellId`, with `areaId` linking it back to your area. An area that is not meshed is one element with the area's own id.
|
|
202
|
+
- **Shell forces** come at each element's corners, in its local axes: membrane forces `F11`, `F22`, `F12` (kN/m), moments `M11`, `M22`, `M12` (kN·m/m, positive with the −3 face in tension, i.e. sagging when local 3 is up), transverse shears `V13`, `V23` (kN/m) and top and bottom face stresses `S11Top` … `S12Bot` (MPa). Elements meeting at a node give different values there, as usual for shell results; average them for a smooth contour.
|
|
203
|
+
- **Members** keep their own ids in every result, even where a meshed edge splits them, and `calculationDetails.memberCount` counts your members.
|
|
204
|
+
|
|
205
|
+
### Running in a Web Worker
|
|
206
|
+
|
|
207
|
+
Model and result are plain JSON, so post the model to a worker, run `analyze` there, and post the result back; the page stays responsive on large models. For big results, analyse with `{ diagrams: "extremes" }`, which keeps every diagram's extremes (so envelopes and `memberDemandEnvelope` still work) but drops the stations, and draw a member's full diagram on demand with `createAnalysis(model).memberDiagram(resultId, memberId)`. The reference has a [worker example](https://theerapat-s28.github.io/ts-structural-eng/fea/#frontend).
|
|
208
|
+
|
|
209
|
+
On a desktop PC (Intel Core i5-13500, Node.js 24):
|
|
210
|
+
|
|
211
|
+
| Model | Analysis time |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| Frame building: 880 nodes, 2 163 members, 3 load cases and 3 combinations | 1.7 s; with `diagrams: "extremes"` the result is 3.8× smaller (15 MB of JSON instead of 57 MB) |
|
|
214
|
+
| Slab on beams and columns: 4 × 4 bays, 2 304 shell elements, 14 556 DOFs | 1.7 s |
|
|
215
|
+
|
|
216
|
+
## API
|
|
217
|
+
|
|
218
|
+
Summarised below; see the [full API reference](https://theerapat-s28.github.io/ts-structural-eng/) for parameter tables, units, warnings and error codes.
|
|
219
|
+
|
|
220
|
+
### FEA — Frame and shell analysis
|
|
221
|
+
|
|
222
|
+
Linear-elastic 3D analysis by the direct stiffness method, from `@theerapat-s28/ts-structural-eng-tools/fea`. Global axes X, Y, Z (Z up); members and shells use ETABS-style local axes 1, 2, 3. Inputs are in mm, MPa, kN, kN·m and kN/m²; results are in kN, kN·m, mm and rad, and shell forces in kN/m, kN·m/m and MPa, as listed in `result.units`.
|
|
223
|
+
|
|
224
|
+
**Renamed in 3.2.0.** A model may have no frame members at all, e.g. a mat foundation, so the exports that apply to the whole model no longer say "frame": `analyzeFrame` → `analyze`, `createFrameAnalysis` → `createAnalysis`, `validateFrameModel` → `validateModel`, `AnalyzeFrameOptions` → `AnalyzeOptions`, `FrameAnalysis` → `Analysis`, and `Frame` → `Fea` in `FeaModel`, `FeaResult`, `FeaCaseResult`, `FeaEnvelope`, `FeaMesh`, `FeaNode`, `FeaId`, `FeaModelIssue`, `FeaErrorDetails`, `FeaError` and `FeaErrors`. The old names still work as deprecated aliases and are removed in 4.0.0.
|
|
225
|
+
|
|
226
|
+
#### Functions
|
|
227
|
+
|
|
228
|
+
- **`analyze(model, options?)`** — Validates the model, analyses every load case and forms every combination by superposition. The stiffness is factorised once for all cases, and combination diagrams are rebuilt from the combined forces, so their extremes are exact rather than sums of case extremes. `options.stations` sets the stations per member diagram (default 21); `options.diagrams: "extremes"` keeps only each diagram's extremes. Returns a `FeaResult`.
|
|
229
|
+
- **`createAnalysis(model, options?)`** — The same analysis, keeping the solution: returns `{ result, memberDiagram(resultId, memberId, stations?) }` to compute a member's full diagram on demand.
|
|
230
|
+
- **`validateModel(model)`** — Checks a model without analysing it and returns every problem, each with `details` (`nodeId`, `memberId`, `areaId`, `shellId`, `edge`, `loadCaseId`, `combinationId`, `field`, `dof`) for highlighting in a UI. `analyze` runs it first and throws the first problem as a `FeaError` whose `issues` lists all of them.
|
|
231
|
+
- **`distributeAreaLoads(model)`** — Returns `{ memberLoads, warnings }`: the member loads that the model's null areas send to their edge members, exactly what `analyze` adds, for checking or previewing. Loads on shells act on the shells and are not included.
|
|
232
|
+
- **`memberConnectivity(model)`** — Returns `{ intermediateNodes, nearMissNodes, warnings }`: the model nodes each member is connected to and the nodes that just miss a member, the same check `analyze` makes, without analysing. It doesn't throw for a model that is still being edited, so a frontend can mark the points on every edit. It also reports a near miss that leaves the model unstable, when `analyze` throws 304 and returns no result.
|
|
233
|
+
- **`memberDemandEnvelope(result, memberId, options?)`** — Reduces a member's diagrams to `MuPositive`, `MuNegative`, `Vu` (optionally from distance `d` off the supports) and `Nu`, enveloped over all combinations (or the `combinations` / `cases` you select), with the `governing` combination of each, for the RC capacity functions.
|
|
234
|
+
- **`rectBeamToSectionProperties(section, options?)`** (from `rc`) — Converts a rectangular RC section into `SectionProperties` (`E`, `G`, `A`, `I22`, `I33`, `J`, `unitWeight`) with the ACI 318-19 6.6.3.1.1 inertia modifiers (0.35 beams, 0.70 columns) and a unit weight for self-weight (default 24 kN/m³, common practice rather than an ACI value).
|
|
235
|
+
- **`beam3dLocalStiffness(E, G, A, I22, I33, J, L)`** — The 12×12 local stiffness matrix exactly as in the reference "Complete Beam Stiffness Matrix". Its bending rotations R2 and R3 follow the opposite sign to the right-hand rule; **`beam3dLocalStiffnessRightHanded`** returns the right-handed form that `analyze` uses.
|
|
236
|
+
- **`memberAxes(start, end, angle?)`** — The ETABS-style local axes of a member as a direction-cosine matrix.
|
|
237
|
+
|
|
238
|
+
#### The model
|
|
239
|
+
|
|
240
|
+
A `FeaModel` is plain data. Every load names its `loadCase`, so loads are flat top-level lists:
|
|
241
|
+
|
|
242
|
+
| Field | What it holds |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| `nodes` | `{ id, x, y, z }` in mm; ids are strings or numbers |
|
|
245
|
+
| `members` | `{ id, startNodeId, endNodeId, section, angle?, releases?, connectIntermediateNodes? }`, with `section` a `SectionProperties`; omit for a model of shells only |
|
|
246
|
+
| `restraints` | Per node, each DOF `ux` … `rz` fixed (`true`) or a spring (kN/mm, kN·m/rad) |
|
|
247
|
+
| `lineRestraints` | `{ nodeIds: [a, b], ux? … rz? }`: fixes those DOFs at every node on the line from `a` to `b`, generated mesh nodes included, e.g. a wall base |
|
|
248
|
+
| `loadCases` | `{ id, name?, type?, selfWeight? }`; `selfWeight: 1` applies the full self-weight of members and shells |
|
|
249
|
+
| `nodalLoads` | `{ loadCase, nodeId, fx? … mz? }` in kN and kN·m |
|
|
250
|
+
| `memberLoads` | Uniform (`"udl"`), `"trapezoidal"` and `"point"` loads in local (`"1"`–`"3"`) or global (`"X"`–`"Z"`) directions, and `"torque"` about the member axis; uniform and trapezoidal loads in a global direction can be per unit projected length (`projected: true`), e.g. snow on a sloped rafter |
|
|
251
|
+
| `areas` | Null areas, `{ id, nodeIds, distribution, supportEdges? }` |
|
|
252
|
+
| `shells` | Shell areas, `{ id, nodeIds, type?, section, angle?, modifiers?, mesh? }` |
|
|
253
|
+
| `areaLoads` | `{ loadCase, areaId, direction, q, projected? }` in kN/m², on a null area or a shell; `direction` is the area's normal `"3"` or a global axis |
|
|
254
|
+
| `combinations` | `{ id, name?, terms }`, each term `{ case, factor }` or `{ combination, factor }`; nested combinations are expanded |
|
|
255
|
+
|
|
256
|
+
#### Members
|
|
257
|
+
|
|
258
|
+
End releases on any of the six end DOFs, full (`true`) or partial fixity (a spring stiffness in series with the member end), with the deformation across each release reported in `releaseDeformations`. Supports are fixed or springs. Joint rotations that no member resists, as at pin-jointed truss joints, are held automatically and listed in `calculationDetails.autoRestrainedDofs`.
|
|
259
|
+
|
|
260
|
+
Draw a girder once, from support to support: a model node lying on a member between its ends, such as where a beam frames in or a column lands mid-span, is connected to it automatically. The member is split there internally and still reported as one member. Each connection is listed in `calculationDetails.intermediateNodes`. A node within 1 % of the member length (at most 100 mm) of a member, but not on it, is not connected: it is listed in `calculationDetails.nearMissNodes` and gets a "Member connectivity" warning, which catches a node that was meant to snap to the member but didn't. Draw both lists in their own colours so users can see that the model connects the way they think, and call `memberConnectivity(model)` to get them while the user draws, without analysing. Set `connectIntermediateNodes: false` on a member to connect it only at its ends.
|
|
261
|
+
|
|
262
|
+
#### Null areas or shells
|
|
263
|
+
|
|
264
|
+
Both are areas that take `areaLoads`, and they share one id namespace.
|
|
265
|
+
|
|
266
|
+
- **A null area** adds no stiffness: it only sends its loads to the members along its edges. It has 3 or 4 nodes forming a planar convex polygon. `"twoWay"` sends each point to its nearest edge (the corner-bisector split, any convex shape); `"oneWay"` spans strips between the listed `supportEdges`, parallel to the unsupported edges, half to each end; `"cantilever"` (rectangles) puts `q·c` and a torque `q·c²/2` on its one support edge. Edges split by intermediate nodes are cut at them. Use it for slabs whose stiffness you leave out of the model.
|
|
267
|
+
- **A shell area** has its own stiffness and shares nodes with members and other shells; use it for walls, cores, transfer slabs and mats. It is a four-node flat shell: a drilling-rotation membrane, so a beam framing into a wall in its plane transfers its moment, and a thin (DKQ) plate. `type` is `"shell"` (both parts, the default), `"membrane"` or `"plate"`. `section` is `{ thickness, E, nu, unitWeight? }`, and `modifiers` scale the membrane (`f11`, `f22`, `f12`) and bending (`m11`, `m22`, `m12`) stiffness and the self-weight (`weight`), e.g. for the cracked-section values of ACI 318-19 Table 6.6.3.1.1. Slightly warped quads are allowed, up to `SHELL_WARPING_LIMIT` (0.1·√A off the plane). Local 3 follows the right-hand rule around `nodeIds`, local 2 points up on walls and local 1 is +X on horizontal shells; `angle` rotates them.
|
|
268
|
+
- **Meshing.** Give a shell `mesh: { maxSize }` (mm) or `mesh: { divisions: [n1, n2] }` and the engine divides it into elements. Neighbouring areas share their mesh nodes, including where an area edge meets another at a node; model nodes on an area edge become mesh nodes; and members along a meshed edge are split there internally. Fix supports along a meshed edge with `lineRestraints`, which reach the generated nodes.
|
|
269
|
+
|
|
270
|
+
#### The result
|
|
271
|
+
|
|
272
|
+
| Field | What it holds |
|
|
273
|
+
| --- | --- |
|
|
274
|
+
| `cases`, `combinations` | Results keyed by id, each with `nodalDisplacements`, `reactions`, `memberEndForces`, `releaseDeformations`, `memberDiagrams` (`N`, `V2`, `V3`, `T`, `M2`, `M3` and deflections `u1`–`u3` local, `ux`–`uz` global, along each member), `shellForces`, an `equilibriumResidual` check and `warnings` |
|
|
275
|
+
| `envelope` | Max and min of every result over the combinations, with the governing combination; absent without combinations |
|
|
276
|
+
| `mesh` | The generated nodes and every shell element with its nodes; absent without shells |
|
|
277
|
+
| `calculationDetails` | Node (generated included), member, shell-element, DOF, load case and combination counts, `profileSize`, `autoRestrainedDofs`, `intermediateNodes` and `nearMissNodes` |
|
|
278
|
+
| `units`, `warnings` | The unit of each kind of result, and the warnings of every case and combination |
|
|
279
|
+
|
|
280
|
+
Invalid models and unstable structures throw `FeaError`, described under [Errors and warnings](#errors-and-warnings-from-core).
|
|
281
|
+
|
|
282
|
+
### RC Beam Design
|
|
283
|
+
|
|
284
|
+
- **`rectBeamMomentCapacity(section)`** — Computes φMn for a rectangular RC beam (singly or doubly reinforced). Returns `phiMn` in kN·m with calculation details and ACI 318-19 warnings. `calculationDetails` reports `c`, `a`, `beta1`, `d`, `As` and `ro` for either section type, plus `d_`, `As_`, `fs_` and `ro_` when compression steel is present.
|
|
285
|
+
- **`rectBeamBarLayout(input)`** — Lays bar groups out into the minimum number of layers that satisfy ACI 318-19 25.2.1 / 25.2.2 spacing, and returns the resulting `d` and `d_` ready to feed into `rectBeamMomentCapacity`. `topBars` is optional; omit it for a section with no top reinforcement.
|
|
286
|
+
- **`concreteShearCapacity(section)`** — Computes φVc, the concrete contribution to shear capacity (ACI 318-19, 22.5.5.1).
|
|
287
|
+
- **`stirrupShearCapacity(section)`** — Computes φVs, the stirrup contribution to shear capacity (ACI 318-19, 22.5.10.5.3).
|
|
288
|
+
- **`checkStirrupRequirement(input)`** — Determines whether stirrups are required, and the required Av/s ratio and max spacing (ACI 318-19, 9.6.3.1, 9.6.3.3, 9.7.6.2.2).
|
|
289
|
+
|
|
290
|
+
### Strengthening
|
|
291
|
+
|
|
292
|
+
- **`calculateSteelJacketedBeamMomentCapacity(section, jacketedProperties)`** — Computes φMn for a beam strengthened with steel plate jacketing, as a `before` / `after` pair. The bottom plate is added to the tension steel and the top plate to the compression steel, which turns an originally singly reinforced section into a doubly reinforced one.
|
|
293
|
+
- **`plateInterfaceShearFlow(input)`** — Computes the shear flow `q = V·Q/I` (N/mm) to transfer across each concrete-to-plate interface, from a cracked (default) or uncracked elastic transformed section. Returns a per-plate `top` / `bottom` result, `null` where a plate is absent.
|
|
294
|
+
- **`boltShearCapacity(bolt)`** — Computes φVsa for one anchor bolt from the steel strength (ACI 318-19, 17.7.1.2b, φ per Table 17.5.3). Concrete breakout and pryout are not evaluated and must be checked separately.
|
|
295
|
+
- **`plateInterfaceBoltRequirement(input)`** — Computes the required bolt pitch and count at each interface, taking the larger of the shear-flow requirement (`s = n·φVbolt / q`) and the count needed to develop the full plate yield force, and reports which one governs.
|
|
296
|
+
|
|
297
|
+
Both plates are independently optional: a plate counts as present only when its width and thickness are both positive, so the same functions cover a bottom-only jacket and a top-and-bottom jacket. Use `hasTopPlate(props)` / `hasBottomPlate(props)` to test for presence.
|
|
298
|
+
|
|
299
|
+
Plates bolted to the sides of the web strengthen the beam in shear instead. ACI 318-19 has no provisions for steel side plates, so two independent models are offered and both return a `before` / `after` pair of `phiVn` (kN) for a continuous plate or discrete strips, with the plate contribution limited by the bolt anchorage and by the ACI 318-19 22.5.1.2 web-crushing cap. Use `hasSidePlate(props)` to test for presence.
|
|
300
|
+
|
|
301
|
+
- **`sidePlateShearCapacityByWebYielding(section, plates)`** — Takes each plate as a supplementary web reaching the von Mises shear yield stress `0.6·fy` (AISC 360 G2.1), and warns on plate slenderness beyond `2.24·√(Es/fy)`.
|
|
302
|
+
- **`sidePlateShearCapacityByTensionTie(section, plates)`** — Takes each plate as a tension tie crossing the diagonal crack, per the bonded shear reinforcement model of ACI 440.2R-17 §11.4 with steel in place of FRP: `ffe = min(fy, Es·0.004)` and `psi_f = 0.85`. Supports inclined strips.
|
|
303
|
+
|
|
304
|
+
ACI 440.2R-17 11.4.2 (spacing, which defers to the ACI 318 limits) and 11.4.3 (`Vs + Vf ≤ 0.66·√f'c·bw·d`) are verified against the guide; the subsections carrying the 0.004 strain cap and `psi_f` are still cited at §11.4 only. See the citation-status note at the top of `src/strengthening/rc-beam-side-plate-shear.ts`.
|
|
305
|
+
- **`compareSidePlateShearCapacity(section, plates)`** — Runs both models and reports the lower `phiVn` as `governing`; the intended entry point for a conservative design capacity.
|
|
306
|
+
|
|
307
|
+
### Concrete properties (from `rc`)
|
|
114
308
|
|
|
115
|
-
|
|
309
|
+
- **`concreteBeta(fc_)`** — ACI 318 β₁ factor
|
|
310
|
+
- **`concreteElasticModulus(fc_)`** — Ec = 4700√f'c (MPa)
|
|
311
|
+
- **`psiToMpa(psi)`** — Unit conversion
|
|
312
|
+
|
|
313
|
+
### Errors and warnings (from `core`)
|
|
314
|
+
|
|
315
|
+
A design that is valid but breaks a code provision returns normally with an entry in `warnings`, citing the clause (e.g. `"ACI318-19, 9.6.1.2"`). A calculation whose assumptions break down throws instead, never returning a silently wrong result:
|
|
316
|
+
|
|
317
|
+
- **`RCDesignError`** — `code` and `message` from `Errors`: 1XX for RC beam design (e.g. 102, tensile steel not yielding; 105, `Vs` above the 22.5.1.2 limit), 2XX for strengthening and plate connections (201–206).
|
|
318
|
+
- **`FeaError`** — `code` and `message` from `FeaErrors`, `details` locating the problem, and `issues` listing every problem `validateModel` found. Codes 301–317 cover the model, members, loads, null areas and combinations (304 is an unstable structure); 326–329 cover shells: 326 invalid geometry, 327 invalid section, 328 a translation that nothing resists at a node connected only to membranes or plates, 329 an area that cannot be meshed. Match on `code`, not on `message`.
|
|
319
|
+
|
|
320
|
+
`core` also exports the shared input types, the type guards `isSinglyReinforced`, `hasTopPlate`, `hasBottomPlate` and `hasSidePlate`, and the engineering constants (φ factors, ultimate concrete strain, inertia modifiers, frame-analysis tolerances, `SHELL_WARPING_LIMIT`).
|
|
321
|
+
|
|
322
|
+
### Utilities (from `utils`)
|
|
116
323
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
324
|
+
Low-level helpers the engine is built on, exported for reuse: `solveQuadratic`, `roundToDecimalPlaces`, `mergeWarnings`, dense matrix helpers (`zeros`, `identity`, `transpose`, `matMul`, `matVec`), Cholesky and general linear solvers (`choleskyFactor`, `choleskySolveFactored`, `choleskySolve`, `solveLinearSystem`), and the skyline solver (`createSkyline`, `skylineAdd`, `skylineGet`, `skylineSize`, `skylineFactor`, `skylineSolve`, `reverseCuthillMcKee`).
|
|
325
|
+
|
|
326
|
+
## Development
|
|
327
|
+
|
|
328
|
+
To work on the library itself you need a current Node.js LTS (22 or later) and pnpm. Install the dependencies with:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
pnpm install
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Scripts
|
|
335
|
+
|
|
336
|
+
| Command | Description |
|
|
337
|
+
| ----------------------- | ------------------------------------------------------------- |
|
|
338
|
+
| `pnpm run dev` | Run [`examples/EX-0001-basic-usage/basic-usage.ts`](examples/EX-0001-basic-usage/basic-usage.ts) against the sources with `ts-node` |
|
|
339
|
+
| `pnpm run build` | Compile `src/` into `dist/` (CommonJS and `.d.ts`) and `dist/esm/` (ES modules) |
|
|
340
|
+
| `pnpm run lint` | Lint source files with ESLint |
|
|
341
|
+
| `pnpm run lint:fix` | Auto-fix lint issues |
|
|
342
|
+
| `pnpm run format` | Format code with Prettier |
|
|
343
|
+
| `pnpm run format:check` | Check formatting without writing |
|
|
344
|
+
| `pnpm run test` | Run unit tests with Vitest |
|
|
345
|
+
| `pnpm run test:watch` | Run tests in watch mode |
|
|
127
346
|
|
|
128
|
-
|
|
347
|
+
### Project layout
|
|
129
348
|
|
|
130
349
|
```
|
|
131
350
|
src/
|
|
@@ -143,6 +362,7 @@ src/
|
|
|
143
362
|
│ └── rc-beam-side-plate-shear.ts # Shear capacity before/after bolted side plates (two models)
|
|
144
363
|
├── fea/ # Finite-element analysis
|
|
145
364
|
│ ├── index.ts
|
|
365
|
+
│ ├── deprecated.ts # Names before 3.2.0 (analyzeFrame, FrameModel, …), aliases until 4.0.0
|
|
146
366
|
│ ├── shared/ # The base every part builds on
|
|
147
367
|
│ │ ├── index.ts
|
|
148
368
|
│ │ ├── types/ # Nodes, restraints, area loads
|
|
@@ -153,7 +373,7 @@ src/
|
|
|
153
373
|
│ │ ├── area/ # Null areas: geometry, edge-member chains, area-load distribution
|
|
154
374
|
│ │ ├── elements/ # Reference beam stiffness matrix, fixed-end forces, end releases and partial-fixity condensation
|
|
155
375
|
│ │ ├── transformation/ # ETABS-style local axes and the 12×12 transformation
|
|
156
|
-
│ │ ├── solver/ # Member pieces, member-load resolution, member assembly helpers
|
|
376
|
+
│ │ ├── solver/ # Member pieces, nodes along members, member-load resolution, member assembly helpers
|
|
157
377
|
│ │ ├── validation/ # Checks on members, member loads and null areas
|
|
158
378
|
│ │ ├── post/ # Member force diagrams
|
|
159
379
|
│ │ └── types/ # Member, member-load and null-area types; member result types
|
|
@@ -167,15 +387,15 @@ src/
|
|
|
167
387
|
│ │ └── types/ # Shell-area model and result types
|
|
168
388
|
│ └── analysis/ # The whole model, members and shells together (direct stiffness method)
|
|
169
389
|
│ ├── index.ts
|
|
170
|
-
│ ├── mesh/ # The analysed model: shell mesh, line restraints, member splitting at mesh nodes
|
|
171
|
-
│ ├── solver/ # System build + skyline factorisation, per-case solve, combinations,
|
|
172
|
-
│ ├── validation/ #
|
|
390
|
+
│ ├── mesh/ # The analysed model: shell mesh, line restraints, member splitting at model and mesh nodes
|
|
391
|
+
│ ├── solver/ # System build + skyline factorisation, per-case solve, combinations, analyze, distributeAreaLoads
|
|
392
|
+
│ ├── validation/ # validateModel: every input problem, with its location
|
|
173
393
|
│ ├── post/ # Result presentation, envelopes, design demands
|
|
174
|
-
│ └── types/ #
|
|
394
|
+
│ └── types/ # FeaModel (load cases, combinations, nodal loads, line restraints) and FeaResult
|
|
175
395
|
├── core/ # Shared infrastructure
|
|
176
396
|
│ ├── index.ts
|
|
177
397
|
│ ├── constants/ # RC design constants (ACI 318) and frame-analysis tolerances
|
|
178
|
-
│ ├── errors/ # RCDesignError and
|
|
398
|
+
│ ├── errors/ # RCDesignError and FeaError with their coded entries
|
|
179
399
|
│ └── types/ # Shared types: RC sections, plate jacketing, section properties, warnings, units
|
|
180
400
|
└── utils/ # Helper utilities
|
|
181
401
|
├── index.ts
|
|
@@ -183,30 +403,33 @@ src/
|
|
|
183
403
|
├── matrix.ts # Dense matrix helpers, Cholesky (factor once, solve many) and general linear solvers
|
|
184
404
|
├── skyline.ts # Skyline (banded) Cholesky solver and reverse Cuthill–McKee ordering
|
|
185
405
|
└── merge-warning.ts # Warning array merging
|
|
186
|
-
examples/
|
|
187
|
-
|
|
406
|
+
examples/ # One folder per example, EX-<number>-<name>
|
|
407
|
+
├── EX-0001-basic-usage/ # RC beam capacity and steel-plate jacketing (pnpm run dev)
|
|
408
|
+
├── EX-0002-slab-on-columns/ # Flat plate on four columns, with its model.json and result.json
|
|
409
|
+
└── EX-0003-shear-wall/ # Meshed shear wall, with its model.json and result.json
|
|
188
410
|
tests/
|
|
189
411
|
├── rc/ # Tests for RC module
|
|
190
412
|
├── strengthening/ # Tests for strengthening module
|
|
191
413
|
├── fea/frame/ # Tests for members and null areas
|
|
192
414
|
├── fea/shell/ # Tests for shell elements, meshing and shell results
|
|
193
415
|
├── fea/shared/ # Tests for element assembly and automatic restraint
|
|
194
|
-
├── fea/analysis/ # Tests for
|
|
416
|
+
├── fea/analysis/ # Tests for analyze, combinations, validation, errors and RC integration
|
|
195
417
|
└── utils/ # Tests for utilities
|
|
196
418
|
html-docs/ # HTML API reference, deployed to GitHub Pages
|
|
197
419
|
├── DESIGN.md # Style guide for the doc pages
|
|
198
420
|
├── index.html # Landing page
|
|
199
421
|
├── rc/index.html
|
|
200
422
|
├── strengthening/index.html
|
|
201
|
-
|
|
423
|
+
├── fea/index.html
|
|
424
|
+
└── shell-element.html # Shell element theory notes
|
|
202
425
|
ROADMAP.md # FEA roadmap and implementation plan (not published)
|
|
203
426
|
.agents/skills/update-version/ # AI agent skill: bump the version and roll the changelog
|
|
204
427
|
.claude/skills/npm-publish/ # AI agent skill: release checklist for publishing to npm
|
|
205
428
|
```
|
|
206
429
|
|
|
207
|
-
|
|
430
|
+
### TypeScript path aliases
|
|
208
431
|
|
|
209
|
-
|
|
432
|
+
The sources import each other through `baseUrl` + `paths` aliases:
|
|
210
433
|
|
|
211
434
|
```jsonc
|
|
212
435
|
"paths": {
|
|
@@ -219,78 +442,17 @@ This project uses `baseUrl` + `paths` for clean imports:
|
|
|
219
442
|
}
|
|
220
443
|
```
|
|
221
444
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
## API
|
|
225
|
-
|
|
226
|
-
Summarised below; see the [full API reference](https://theerapat-s28.github.io/ts-structural-eng/) for parameter tables, units, warnings and error codes.
|
|
227
|
-
|
|
228
|
-
### RC Beam Design
|
|
229
|
-
|
|
230
|
-
- **`rectBeamMomentCapacity(section)`** — Computes φMn for a rectangular RC beam (singly or doubly reinforced). Returns `phiMn` in kN·m with calculation details and ACI 318-19 warnings. `calculationDetails` reports `c`, `a`, `beta1`, `d`, `As` and `ro` for either section type, plus `d_`, `As_`, `fs_` and `ro_` when compression steel is present.
|
|
231
|
-
- **`rectBeamBarLayout(input)`** — Lays bar groups out into the minimum number of layers that satisfy ACI 318-19 25.2.1 / 25.2.2 spacing, and returns the resulting `d` and `d_` ready to feed into `rectBeamMomentCapacity`. `topBars` is optional; omit it for a section with no top reinforcement.
|
|
232
|
-
- **`concreteShearCapacity(section)`** — Computes φVc, the concrete contribution to shear capacity (ACI 318-19, 22.5.5.1).
|
|
233
|
-
- **`stirrupShearCapacity(section)`** — Computes φVs, the stirrup contribution to shear capacity (ACI 318-19, 22.5.10.5.3).
|
|
234
|
-
- **`checkStirrupRequirement(input)`** — Determines whether stirrups are required, and the required Av/s ratio and max spacing (ACI 318-19, 9.6.3.1, 9.6.3.3, 9.7.6.2.2).
|
|
235
|
-
|
|
236
|
-
### Strengthening
|
|
237
|
-
|
|
238
|
-
- **`calculateSteelJacketedBeamMomentCapacity(section, jacketedProperties)`** — Computes φMn for a beam strengthened with steel plate jacketing, as a `before` / `after` pair. The bottom plate is added to the tension steel and the top plate to the compression steel, which turns an originally singly reinforced section into a doubly reinforced one.
|
|
239
|
-
- **`plateInterfaceShearFlow(input)`** — Computes the shear flow `q = V·Q/I` (N/mm) to transfer across each concrete-to-plate interface, from a cracked (default) or uncracked elastic transformed section. Returns a per-plate `top` / `bottom` result, `null` where a plate is absent.
|
|
240
|
-
- **`boltShearCapacity(bolt)`** — Computes φVsa for one anchor bolt from the steel strength (ACI 318-19, 17.7.1.2b, φ per Table 17.5.3). Concrete breakout and pryout are not evaluated and must be checked separately.
|
|
241
|
-
- **`plateInterfaceBoltRequirement(input)`** — Computes the required bolt pitch and count at each interface, taking the larger of the shear-flow requirement (`s = n·φVbolt / q`) and the count needed to develop the full plate yield force, and reports which one governs.
|
|
242
|
-
|
|
243
|
-
Both plates are independently optional: a plate counts as present only when its width and thickness are both positive, so the same functions cover a bottom-only jacket and a top-and-bottom jacket. Use `hasTopPlate(props)` / `hasBottomPlate(props)` to test for presence.
|
|
244
|
-
|
|
245
|
-
Plates bolted to the sides of the web strengthen the beam in shear instead. ACI 318-19 has no provisions for steel side plates, so two independent models are offered and both return a `before` / `after` pair of `phiVn` (kN) for a continuous plate or discrete strips, with the plate contribution limited by the bolt anchorage and by the ACI 318-19 22.5.1.2 web-crushing cap. Use `hasSidePlate(props)` to test for presence.
|
|
246
|
-
|
|
247
|
-
- **`sidePlateShearCapacityByWebYielding(section, plates)`** — Takes each plate as a supplementary web reaching the von Mises shear yield stress `0.6·fy` (AISC 360 G2.1), and warns on plate slenderness beyond `2.24·√(Es/fy)`.
|
|
248
|
-
- **`sidePlateShearCapacityByTensionTie(section, plates)`** — Takes each plate as a tension tie crossing the diagonal crack, per the bonded shear reinforcement model of ACI 440.2R-17 §11.4 with steel in place of FRP: `ffe = min(fy, Es·0.004)` and `psi_f = 0.85`. Supports inclined strips.
|
|
249
|
-
|
|
250
|
-
ACI 440.2R-17 11.4.2 (spacing, which defers to the ACI 318 limits) and 11.4.3 (`Vs + Vf ≤ 0.66·√f'c·bw·d`) are verified against the guide; the subsections carrying the 0.004 strain cap and `psi_f` are still cited at §11.4 only. See the citation-status note at the top of `src/strengthening/rc-beam-side-plate-shear.ts`.
|
|
251
|
-
- **`compareSidePlateShearCapacity(section, plates)`** — Runs both models and reports the lower `phiVn` as `governing`; the intended entry point for a conservative design capacity.
|
|
252
|
-
|
|
253
|
-
### FEA — Frame Analysis
|
|
254
|
-
|
|
255
|
-
Linear-elastic 3D frame analysis by the direct stiffness method, imported from `@theerapat-s28/ts-structural-eng-tools/fea`. Global axes X, Y, Z (Z up) and ETABS-style local axes 1, 2, 3; inputs in mm, MPa, kN and kN·m, results in kN, kN·m, mm and rad.
|
|
256
|
-
|
|
257
|
-
- **`analyzeFrame(model, options?)`** — Analyses every load case in `model.loadCases` (dead, superimposed dead, live, wind…, each with an optional `selfWeight` multiplier) and forms every combination in `model.combinations` by superposition. The loads are flat top-level lists, `model.nodalLoads` and `model.memberLoads` (uniform, trapezoidal and point loads in local or global directions, and torques about the member axis; uniform and trapezoidal loads in a global direction can be given per unit projected length with `projected: true`, e.g. snow on a sloped rafter), each load tagged with its `loadCase`, so large models stay readable. Area loads (`model.areaLoads`, kN/m²) on null areas (`model.areas`) are first distributed to the members along each area's edges — see `distributeAreaLoads`. Shell areas (`model.shells`, `{ id, nodeIds, type?, section: { thickness, E, nu, unitWeight? }, angle?, modifiers? }`) are four-node flat shell elements with their own stiffness — a drilling-rotation membrane and a thin (DKQ) plate, as `"shell"`, `"membrane"` or `"plate"` — for walls, cores and slabs; they share nodes with members, take `areaLoads` naming their id and self-weight as corner forces, and accept cracked-section modifiers (`f11`…`m12`). Give an area `mesh: { maxSize }` (or `{ divisions }`) and the engine meshes it: neighbouring areas, including T-junctions, share their mesh nodes, model nodes on an area edge become mesh nodes, and members along meshed edges are split internally while their results stay under their own id; `model.lineRestraints` (`{ nodeIds: [a, b], ux?…rz? }`) fix every node on a line, generated nodes included, and `result.mesh` lists the generated nodes and elements. A translation that nothing resists at a node connected only to membranes or plates throws 328, an area that cannot be meshed 329. Each case and combination reports `shellForces` — per shell and corner, membrane forces `F11`, `F22`, `F12` (kN/m), moments `M11`, `M22`, `M12` (kN·m/m, sagging positive), shears `V13`, `V23` and top/bottom stresses — and the envelope has them per corner. A combination is a list of factored terms `{ case, factor }` or `{ combination, factor }`; factors are entered by the user, and nested combinations are expanded. Supports end releases — full (`true`) or partial fixity (a spring stiffness in series with the member end) on any of the six end DOFs, with the deformation across each release reported in `releaseDeformations` — and fixed or spring supports. Joint rotations that no member resists, as at pin-jointed truss joints, are held automatically and listed in `calculationDetails.autoRestrainedDofs`. The stiffness matrix is factorised once for all cases. Returns `cases` and `combinations` keyed by id — each with displacements, reactions, member end forces, member diagrams along each member (forces `N`, `V2`, `V3`, `T`, `M2`, `M3` and deflections `u1`–`u3` local / `ux`–`uz` global, ready for plotting) and an equilibrium check — and an `envelope` of max/min over the combinations with the governing combination. Combination diagrams are rebuilt exactly, not summed from case extremes. The stiffness is stored in skyline (banded) form with nodes in reverse Cuthill–McKee order, so a building of ~850 nodes runs in about 1.5 s. Model and result are plain JSON, so it runs in a Web Worker. Invalid models, load cases or combinations and mechanisms throw `FrameAnalysisError` (codes 301–317 and 326–329) with `details` locating the problem.
|
|
258
|
-
- **`createFrameAnalysis(model, options?)`** — Same analysis, keeping the solution: returns `{ result, memberDiagram(resultId, memberId) }` so full member diagrams can be computed on demand. Combine with `options.diagrams: "extremes"`, which keeps diagram extremes (and the envelope) but drops the station arrays, for results about 4× smaller on large models.
|
|
259
|
-
- **`validateFrameModel(model)`** — Checks a model without analysing it and returns every problem, each with `details` (`nodeId`, `memberId`, `areaId`, `shellId`, `edge`, `loadCaseId`, `combinationId`, `field`, `dof`) for highlighting in a UI. `analyzeFrame` runs it first and throws the first problem as a `FrameAnalysisError` whose `issues` lists all of them; non-finite numbers, negative springs, invalid end-release values and unknown option values are rejected (314).
|
|
260
|
-
- **`distributeAreaLoads(model)`** — Returns `{ memberLoads, warnings }`: the member loads that the model's null areas send to their edge members, exactly what `analyzeFrame` adds, for checking or previewing (loads on shell areas act on the shells and are not included). A null area (`{ id, nodeIds, distribution, supportEdges? }`) has 3 or 4 nodes forming a planar convex polygon and adds no stiffness. `"twoWay"` sends each point to its nearest edge (the corner-bisector split, any convex shape); `"oneWay"` spans strips between the listed `supportEdges`, parallel to the unsupported edges, half to each end; `"cantilever"` (rectangles) puts `q·c` and a torque `q·c²/2` on its one support edge. Area loads (`{ loadCase, areaId, direction: "3" | "X" | "Y" | "Z", q, projected? }`) are per unit true area, `"3"` being the area's normal; with `projected: true` and a global direction, `q` is per unit projected area (e.g. per plan area on a ramp) and is converted to true area before distribution. Edges split by intermediate nodes are cut at them. Area problems throw 315 (geometry), 316 (an edge without members) or 317 (supports that do not fit the distribution).
|
|
261
|
-
- **`memberDemandEnvelope(result, memberId, options?)`** — Reduces a member's diagrams to `MuPositive`, `MuNegative`, `Vu` (optionally at distance `d` from the supports) and `Nu`, enveloped over all combinations (or the `combinations` / `cases` you select), with the `governing` combination of each, for the RC capacity functions.
|
|
262
|
-
- **`rectBeamToSectionProperties(section, options?)`** (from `rc`) — Converts a rectangular RC section into `SectionProperties` (`E`, `G`, `A`, `I22`, `I33`, `J`, `unitWeight`) with the ACI 318-19 6.6.3.1.1 inertia modifiers (0.35 beams, 0.70 columns) and a unit weight for self-weight (default 24 kN/m³, common practice rather than an ACI value).
|
|
263
|
-
- **`beam3dLocalStiffness(E, G, A, I22, I33, J, L)`** — The 12×12 local stiffness matrix exactly as in the reference "Complete Beam Stiffness Matrix". Its bending rotations R2 and R3 follow the opposite sign to the right-hand rule; **`beam3dLocalStiffnessRightHanded`** returns the right-handed form that `analyzeFrame` uses.
|
|
264
|
-
- **`memberAxes(start, end, angle?)`** — The ETABS-style local axes of a member as a direction-cosine matrix.
|
|
265
|
-
|
|
266
|
-
### Concrete properties (from `rc`)
|
|
267
|
-
|
|
268
|
-
- **`concreteBeta(fc_)`** — ACI 318 β₁ factor
|
|
269
|
-
- **`concreteElasticModulus(fc_)`** — Ec = 4700√f'c (MPa)
|
|
270
|
-
- **`psiToMpa(psi)`** — Unit conversion
|
|
271
|
-
|
|
272
|
-
### Errors and warnings (from `core`)
|
|
273
|
-
|
|
274
|
-
A design that is valid but breaks a code provision returns normally with an entry in `warnings`, citing the clause (e.g. `"ACI318-19, 9.6.1.2"`). A calculation whose assumptions break down throws instead, never returning a silently wrong result:
|
|
275
|
-
|
|
276
|
-
- **`RCDesignError`** — `code` and `message` from `Errors`: 1XX for RC beam design (e.g. 102, tensile steel not yielding; 105, `Vs` above the 22.5.1.2 limit), 2XX for strengthening and plate connections (201–206).
|
|
277
|
-
- **`FrameAnalysisError`** — `code` from `FrameErrors` (301–317), `details` locating the problem, and `issues` listing every problem `validateFrameModel` found.
|
|
278
|
-
|
|
279
|
-
`core` also exports the shared input types, the type guards `isSinglyReinforced`, `hasTopPlate`, `hasBottomPlate` and `hasSidePlate`, and the engineering constants (φ factors, ultimate concrete strain, inertia modifiers, frame-analysis tolerances).
|
|
280
|
-
|
|
281
|
-
### Utilities (from `utils`)
|
|
282
|
-
|
|
283
|
-
Low-level helpers the engine is built on, exported for reuse: `solveQuadratic`, `roundToDecimalPlaces`, `mergeWarnings`, dense matrix helpers (`zeros`, `identity`, `transpose`, `matMul`, `matVec`), Cholesky and general linear solvers (`choleskyFactor`, `choleskySolveFactored`, `choleskySolve`, `solveLinearSystem`), and the skyline solver (`createSkyline`, `skylineAdd`, `skylineGet`, `skylineSize`, `skylineFactor`, `skylineSolve`, `reverseCuthillMcKee`).
|
|
445
|
+
They are duplicated in `vitest.config.ts`, registered at runtime by `tsconfig-paths` in the `dev` script, and rewritten into relative paths by `tsc-alias` when building.
|
|
284
446
|
|
|
285
|
-
|
|
447
|
+
### Build
|
|
286
448
|
|
|
287
449
|
```bash
|
|
288
450
|
pnpm run build
|
|
289
451
|
```
|
|
290
452
|
|
|
291
|
-
The build emits a CommonJS build in `dist/` (for `require`, with the `.d.ts` types) and an ES-module build in `dist/esm/` (for `import` and bundlers such as Vite); `package.json` `exports` routes each subpath to the right one, and `"sideEffects": false` lets bundlers drop unused code. `
|
|
453
|
+
The build emits a CommonJS build in `dist/` (for `require`, with the `.d.ts` types) and an ES-module build in `dist/esm/` (for `import` and bundlers such as Vite); `package.json` `exports` routes each subpath to the right one, and `"sideEffects": false` lets bundlers drop unused code. Only `dist/`, `README.md`, `CHANGELOG.md` and `LICENSE` are published.
|
|
292
454
|
|
|
293
|
-
|
|
455
|
+
### Tests
|
|
294
456
|
|
|
295
457
|
```bash
|
|
296
458
|
pnpm run test # all tests
|
|
@@ -299,7 +461,7 @@ pnpm vitest run tests/rc/rc-beam-design.test.ts # one file
|
|
|
299
461
|
|
|
300
462
|
Tests live in `tests/`, mirroring `src/`, and check results against hand-calculated or textbook values.
|
|
301
463
|
|
|
302
|
-
|
|
464
|
+
### Releasing
|
|
303
465
|
|
|
304
466
|
Releases follow semantic versioning and are published to npm with tags `vX.Y.Z`. What changed in each version is in [CHANGELOG.md](CHANGELOG.md). Preparing a version (changelog, version number, checks) is described in [`.agents/skills/update-version/SKILL.md`](.agents/skills/update-version/SKILL.md), and publishing (release commit and tag, dry run, publish, push tags) in [`.claude/skills/npm-publish/SKILL.md`](.claude/skills/npm-publish/SKILL.md).
|
|
305
467
|
|
|
@@ -32,3 +32,11 @@ export declare const DRILLING_PENALTY_RATIO = 1;
|
|
|
32
32
|
* twisted beam, 0.024, is within 0.5 %); beyond this the element is rejected (326).
|
|
33
33
|
*/
|
|
34
34
|
export declare const SHELL_WARPING_LIMIT = 0.1;
|
|
35
|
+
/**
|
|
36
|
+
* A model node that lies off a member's axis, between its ends, by no more than this fraction
|
|
37
|
+
* of the member's length (and at most `NODE_NEAR_MEMBER_MAX_DISTANCE`), but not on it, gets a
|
|
38
|
+
* warning: it is probably meant to be on the member, yet it is not connected to it.
|
|
39
|
+
*/
|
|
40
|
+
export declare const NODE_NEAR_MEMBER_RATIO = 0.01;
|
|
41
|
+
/** Upper bound (mm) of the near-miss distance given by `NODE_NEAR_MEMBER_RATIO`. */
|
|
42
|
+
export declare const NODE_NEAR_MEMBER_MAX_DISTANCE = 100;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SHELL_WARPING_LIMIT = exports.DRILLING_PENALTY_RATIO = exports.AREA_GEOMETRY_TOLERANCE = exports.EQUILIBRIUM_TOLERANCE = exports.SINGULARITY_TOLERANCE = exports.VERTICAL_MEMBER_TOLERANCE = exports.CONCRETE_UNIT_WEIGHT = exports.COLUMN_INERTIA_MODIFIER = exports.BEAM_INERTIA_MODIFIER = exports.CONCRETE_POISSON_RATIO = void 0;
|
|
3
|
+
exports.NODE_NEAR_MEMBER_MAX_DISTANCE = exports.NODE_NEAR_MEMBER_RATIO = exports.SHELL_WARPING_LIMIT = exports.DRILLING_PENALTY_RATIO = exports.AREA_GEOMETRY_TOLERANCE = exports.EQUILIBRIUM_TOLERANCE = exports.SINGULARITY_TOLERANCE = exports.VERTICAL_MEMBER_TOLERANCE = exports.CONCRETE_UNIT_WEIGHT = exports.COLUMN_INERTIA_MODIFIER = exports.BEAM_INERTIA_MODIFIER = exports.CONCRETE_POISSON_RATIO = void 0;
|
|
4
4
|
/** Poisson's ratio of concrete, for G = E / (2(1 + ν)). */
|
|
5
5
|
exports.CONCRETE_POISSON_RATIO = 0.2;
|
|
6
6
|
/** ACI 318-19 Table 6.6.3.1.1(a): effective I of beams for elastic analysis at factored load. */
|
|
@@ -35,4 +35,12 @@ exports.DRILLING_PENALTY_RATIO = 1;
|
|
|
35
35
|
* twisted beam, 0.024, is within 0.5 %); beyond this the element is rejected (326).
|
|
36
36
|
*/
|
|
37
37
|
exports.SHELL_WARPING_LIMIT = 0.1;
|
|
38
|
+
/**
|
|
39
|
+
* A model node that lies off a member's axis, between its ends, by no more than this fraction
|
|
40
|
+
* of the member's length (and at most `NODE_NEAR_MEMBER_MAX_DISTANCE`), but not on it, gets a
|
|
41
|
+
* warning: it is probably meant to be on the member, yet it is not connected to it.
|
|
42
|
+
*/
|
|
43
|
+
exports.NODE_NEAR_MEMBER_RATIO = 0.01;
|
|
44
|
+
/** Upper bound (mm) of the near-miss distance given by `NODE_NEAR_MEMBER_RATIO`. */
|
|
45
|
+
exports.NODE_NEAR_MEMBER_MAX_DISTANCE = 100;
|
|
38
46
|
//# sourceMappingURL=frame.constant.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.constant.js","sourceRoot":"","sources":["../../../src/core/constants/frame.constant.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iGAAiG;AACpF,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,mGAAmG;AACtF,QAAA,uBAAuB,GAAG,GAAG,CAAC;AAE3C,qGAAqG;AACxF,QAAA,oBAAoB,GAAG,EAAE,CAAC;AAEvC,gGAAgG;AACnF,QAAA,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,2EAA2E;AAC9D,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C;;;GAGG;AACU,QAAA,uBAAuB,GAAG,IAAI,CAAC;AAE5C;;;;;;GAMG;AACU,QAAA,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;GAKG;AACU,QAAA,mBAAmB,GAAG,GAAG,CAAC"}
|
|
1
|
+
{"version":3,"file":"frame.constant.js","sourceRoot":"","sources":["../../../src/core/constants/frame.constant.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iGAAiG;AACpF,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,mGAAmG;AACtF,QAAA,uBAAuB,GAAG,GAAG,CAAC;AAE3C,qGAAqG;AACxF,QAAA,oBAAoB,GAAG,EAAE,CAAC;AAEvC,gGAAgG;AACnF,QAAA,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,2EAA2E;AAC9D,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C;;;GAGG;AACU,QAAA,uBAAuB,GAAG,IAAI,CAAC;AAE5C;;;;;;GAMG;AACU,QAAA,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;GAKG;AACU,QAAA,mBAAmB,GAAG,GAAG,CAAC;AAEvC;;;;GAIG;AACU,QAAA,sBAAsB,GAAG,IAAI,CAAC;AAE3C,oFAAoF;AACvE,QAAA,6BAA6B,GAAG,GAAG,CAAC"}
|