@theerapat-s28/ts-structural-eng-tools 1.4.0 → 2.0.1
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/README.md +44 -4
- package/dist/core/constants/frame.constant.d.ts +14 -0
- package/dist/core/constants/frame.constant.js +18 -0
- package/dist/core/constants/frame.constant.js.map +1 -0
- package/dist/core/constants/rc.constant.d.ts +7 -0
- package/dist/core/constants/rc.constant.js +20 -1
- package/dist/core/constants/rc.constant.js.map +1 -1
- package/dist/core/errors/frame-analysis.error.d.ts +33 -0
- package/dist/core/errors/frame-analysis.error.js +74 -0
- package/dist/core/errors/frame-analysis.error.js.map +1 -0
- package/dist/core/errors/rc-design.error.js +8 -0
- package/dist/core/errors/rc-design.error.js.map +1 -1
- package/dist/core/index.d.ts +7 -3
- package/dist/core/index.js +16 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/types/plate-jacketing.type.d.ts +37 -0
- package/dist/core/types/plate-jacketing.type.js +8 -0
- package/dist/core/types/plate-jacketing.type.js.map +1 -1
- package/dist/core/types/section-properties.type.d.ts +13 -0
- package/dist/core/types/section-properties.type.js +3 -0
- package/dist/core/types/section-properties.type.js.map +1 -0
- package/dist/esm/core/constants/frame.constant.js +15 -0
- package/dist/esm/core/constants/frame.constant.js.map +1 -0
- package/dist/esm/core/constants/rc.constant.js +63 -0
- package/dist/esm/core/constants/rc.constant.js.map +1 -0
- package/dist/esm/core/errors/frame-analysis.error.js +70 -0
- package/dist/esm/core/errors/frame-analysis.error.js.map +1 -0
- package/dist/esm/core/errors/rc-design.error.js +64 -0
- package/dist/esm/core/errors/rc-design.error.js.map +1 -0
- package/dist/esm/core/index.js +9 -0
- package/dist/esm/core/index.js.map +1 -0
- package/dist/esm/core/types/output-message.type.js +2 -0
- package/dist/esm/core/types/output-message.type.js.map +1 -0
- package/dist/esm/core/types/plate-jacketing.type.js +18 -0
- package/dist/esm/core/types/plate-jacketing.type.js.map +1 -0
- package/dist/esm/core/types/rc-beam.type.js +11 -0
- package/dist/esm/core/types/rc-beam.type.js.map +1 -0
- package/dist/esm/core/types/section-properties.type.js +2 -0
- package/dist/esm/core/types/section-properties.type.js.map +1 -0
- package/dist/esm/core/types/unit.type.js +2 -0
- package/dist/esm/core/types/unit.type.js.map +1 -0
- package/dist/esm/fea/frame/elements/beam-3d-stiffness.js +84 -0
- package/dist/esm/fea/frame/elements/beam-3d-stiffness.js.map +1 -0
- package/dist/esm/fea/frame/elements/fixed-end-forces.js +75 -0
- package/dist/esm/fea/frame/elements/fixed-end-forces.js.map +1 -0
- package/dist/esm/fea/frame/elements/static-condensation.js +55 -0
- package/dist/esm/fea/frame/elements/static-condensation.js.map +1 -0
- package/dist/esm/fea/frame/index.js +6 -0
- package/dist/esm/fea/frame/index.js.map +1 -0
- package/dist/esm/fea/frame/post/demand-envelope.js +97 -0
- package/dist/esm/fea/frame/post/demand-envelope.js.map +1 -0
- package/dist/esm/fea/frame/post/envelope.js +59 -0
- package/dist/esm/fea/frame/post/envelope.js.map +1 -0
- package/dist/esm/fea/frame/post/member-diagram.js +332 -0
- package/dist/esm/fea/frame/post/member-diagram.js.map +1 -0
- package/dist/esm/fea/frame/post/present-state.js +106 -0
- package/dist/esm/fea/frame/post/present-state.js.map +1 -0
- package/dist/esm/fea/frame/solver/analyze-frame.js +123 -0
- package/dist/esm/fea/frame/solver/analyze-frame.js.map +1 -0
- package/dist/esm/fea/frame/solver/boundary-conditions.js +33 -0
- package/dist/esm/fea/frame/solver/boundary-conditions.js.map +1 -0
- package/dist/esm/fea/frame/solver/combinations.js +69 -0
- package/dist/esm/fea/frame/solver/combinations.js.map +1 -0
- package/dist/esm/fea/frame/solver/frame-system.js +122 -0
- package/dist/esm/fea/frame/solver/frame-system.js.map +1 -0
- package/dist/esm/fea/frame/solver/global-assembly.js +27 -0
- package/dist/esm/fea/frame/solver/global-assembly.js.map +1 -0
- package/dist/esm/fea/frame/solver/load-case-solver.js +119 -0
- package/dist/esm/fea/frame/solver/load-case-solver.js.map +1 -0
- package/dist/esm/fea/frame/transformation/coordinate-transform.js +71 -0
- package/dist/esm/fea/frame/transformation/coordinate-transform.js.map +1 -0
- package/dist/esm/fea/frame/types/model.type.js +2 -0
- package/dist/esm/fea/frame/types/model.type.js.map +1 -0
- package/dist/esm/fea/frame/types/results.type.js +2 -0
- package/dist/esm/fea/frame/types/results.type.js.map +1 -0
- package/dist/esm/fea/frame/validation/validate-model.js +292 -0
- package/dist/esm/fea/frame/validation/validate-model.js.map +1 -0
- package/dist/esm/fea/index.js +3 -0
- package/dist/esm/fea/index.js.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/rc/general.js +32 -0
- package/dist/esm/rc/general.js.map +1 -0
- package/dist/esm/rc/index.js +5 -0
- package/dist/esm/rc/index.js.map +1 -0
- package/dist/esm/rc/rc-bar-layout.js +89 -0
- package/dist/esm/rc/rc-bar-layout.js.map +1 -0
- package/dist/esm/rc/rc-beam-design.js +320 -0
- package/dist/esm/rc/rc-beam-design.js.map +1 -0
- package/dist/esm/rc/rc-section-properties.js +55 -0
- package/dist/esm/rc/rc-section-properties.js.map +1 -0
- package/dist/esm/strengthening/index.js +4 -0
- package/dist/esm/strengthening/index.js.map +1 -0
- package/dist/esm/strengthening/rc-beam-plate-interface-bolts.js +338 -0
- package/dist/esm/strengthening/rc-beam-plate-interface-bolts.js.map +1 -0
- package/dist/esm/strengthening/rc-beam-side-plate-shear.js +381 -0
- package/dist/esm/strengthening/rc-beam-side-plate-shear.js.map +1 -0
- package/dist/esm/strengthening/rc-beam-steel-plate-jacketing.js +90 -0
- package/dist/esm/strengthening/rc-beam-steel-plate-jacketing.js.map +1 -0
- package/dist/esm/utils/index.js +5 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/math.js +30 -0
- package/dist/esm/utils/math.js.map +1 -0
- package/dist/esm/utils/matrix.js +145 -0
- package/dist/esm/utils/matrix.js.map +1 -0
- package/dist/esm/utils/merge-warning.js +11 -0
- package/dist/esm/utils/merge-warning.js.map +1 -0
- package/dist/esm/utils/skyline.js +151 -0
- package/dist/esm/utils/skyline.js.map +1 -0
- package/dist/fea/frame/elements/beam-3d-stiffness.d.ts +29 -0
- package/dist/fea/frame/elements/beam-3d-stiffness.js +90 -0
- package/dist/fea/frame/elements/beam-3d-stiffness.js.map +1 -0
- package/dist/fea/frame/elements/fixed-end-forces.d.ts +22 -0
- package/dist/fea/frame/elements/fixed-end-forces.js +79 -0
- package/dist/fea/frame/elements/fixed-end-forces.js.map +1 -0
- package/dist/fea/frame/elements/static-condensation.d.ts +19 -0
- package/dist/fea/frame/elements/static-condensation.js +59 -0
- package/dist/fea/frame/elements/static-condensation.js.map +1 -0
- package/dist/fea/frame/index.d.ts +9 -0
- package/dist/fea/frame/index.js +16 -0
- package/dist/fea/frame/index.js.map +1 -0
- package/dist/fea/frame/post/demand-envelope.d.ts +36 -0
- package/dist/fea/frame/post/demand-envelope.js +101 -0
- package/dist/fea/frame/post/demand-envelope.js.map +1 -0
- package/dist/fea/frame/post/envelope.d.ts +8 -0
- package/dist/fea/frame/post/envelope.js +63 -0
- package/dist/fea/frame/post/envelope.js.map +1 -0
- package/dist/fea/frame/post/member-diagram.d.ts +26 -0
- package/dist/fea/frame/post/member-diagram.js +336 -0
- package/dist/fea/frame/post/member-diagram.js.map +1 -0
- package/dist/fea/frame/post/present-state.d.ts +19 -0
- package/dist/fea/frame/post/present-state.js +111 -0
- package/dist/fea/frame/post/present-state.js.map +1 -0
- package/dist/fea/frame/solver/analyze-frame.d.ts +67 -0
- package/dist/fea/frame/solver/analyze-frame.js +128 -0
- package/dist/fea/frame/solver/analyze-frame.js.map +1 -0
- package/dist/fea/frame/solver/boundary-conditions.d.ts +14 -0
- package/dist/fea/frame/solver/boundary-conditions.js +37 -0
- package/dist/fea/frame/solver/boundary-conditions.js.map +1 -0
- package/dist/fea/frame/solver/combinations.d.ts +11 -0
- package/dist/fea/frame/solver/combinations.js +73 -0
- package/dist/fea/frame/solver/combinations.js.map +1 -0
- package/dist/fea/frame/solver/frame-system.d.ts +42 -0
- package/dist/fea/frame/solver/frame-system.js +126 -0
- package/dist/fea/frame/solver/frame-system.js.map +1 -0
- package/dist/fea/frame/solver/global-assembly.d.ts +17 -0
- package/dist/fea/frame/solver/global-assembly.js +33 -0
- package/dist/fea/frame/solver/global-assembly.js.map +1 -0
- package/dist/fea/frame/solver/load-case-solver.d.ts +34 -0
- package/dist/fea/frame/solver/load-case-solver.js +124 -0
- package/dist/fea/frame/solver/load-case-solver.js.map +1 -0
- package/dist/fea/frame/transformation/coordinate-transform.d.ts +21 -0
- package/dist/fea/frame/transformation/coordinate-transform.js +76 -0
- package/dist/fea/frame/transformation/coordinate-transform.js.map +1 -0
- package/dist/fea/frame/types/model.type.d.ts +112 -0
- package/dist/fea/frame/types/model.type.js +3 -0
- package/dist/fea/frame/types/model.type.js.map +1 -0
- package/dist/fea/frame/types/results.type.d.ts +134 -0
- package/dist/fea/frame/types/results.type.js +3 -0
- package/dist/fea/frame/types/results.type.js.map +1 -0
- package/dist/fea/frame/validation/validate-model.d.ts +18 -0
- package/dist/fea/frame/validation/validate-model.js +298 -0
- package/dist/fea/frame/validation/validate-model.js.map +1 -0
- package/dist/fea/index.d.ts +1 -0
- package/dist/fea/index.js +19 -0
- package/dist/fea/index.js.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.js +44 -1
- package/dist/index.js.map +1 -1
- package/dist/rc/index.d.ts +2 -0
- package/dist/rc/index.js +3 -1
- package/dist/rc/index.js.map +1 -1
- package/dist/rc/rc-section-properties.d.ts +35 -0
- package/dist/rc/rc-section-properties.js +59 -0
- package/dist/rc/rc-section-properties.js.map +1 -0
- package/dist/strengthening/index.d.ts +1 -0
- package/dist/strengthening/index.js +5 -1
- package/dist/strengthening/index.js.map +1 -1
- package/dist/strengthening/rc-beam-side-plate-shear.d.ts +254 -0
- package/dist/strengthening/rc-beam-side-plate-shear.js +420 -0
- package/dist/strengthening/rc-beam-side-plate-shear.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +19 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/matrix.d.ts +45 -0
- package/dist/utils/matrix.js +157 -0
- package/dist/utils/matrix.js.map +1 -0
- package/dist/utils/skyline.d.ts +49 -0
- package/dist/utils/skyline.js +161 -0
- package/dist/utils/skyline.js.map +1 -0
- package/package.json +20 -2
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { buildEnvelope } from "../post/envelope.js";
|
|
2
|
+
import { presentMemberDiagram, presentState } from "../post/present-state.js";
|
|
3
|
+
import { throwIssues, validateFrameModel } from "../validation/validate-model.js";
|
|
4
|
+
import { resolveCombinations } from "./combinations.js";
|
|
5
|
+
import { prepareFrameSystem } from "./frame-system.js";
|
|
6
|
+
import { combineStates, solveLoadCase } from "./load-case-solver.js";
|
|
7
|
+
/** Groups loads by their load case id, keeping the input order within each case. */
|
|
8
|
+
const groupByCase = (loads = []) => {
|
|
9
|
+
const groups = new Map();
|
|
10
|
+
for (const load of loads) {
|
|
11
|
+
const group = groups.get(load.loadCase);
|
|
12
|
+
if (group)
|
|
13
|
+
group.push(load);
|
|
14
|
+
else
|
|
15
|
+
groups.set(load.loadCase, [load]);
|
|
16
|
+
}
|
|
17
|
+
return groups;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Analyses a 3D frame like `analyzeFrame` and keeps the solution, so that full member diagrams
|
|
21
|
+
* can be requested later one member at a time — e.g. analyse with `diagrams: "extremes"` and
|
|
22
|
+
* draw a member's diagram when the user selects it. Run it in a Web Worker for large models.
|
|
23
|
+
*
|
|
24
|
+
* @param model - Nodes, members, restraints, load cases, loads tagged with their load case,
|
|
25
|
+
* and combinations
|
|
26
|
+
* @param options - Diagram station count and detail
|
|
27
|
+
* @returns `{ result, memberDiagram }`
|
|
28
|
+
* @throws {FrameAnalysisError} 301–314 for an invalid model (with `details` and every problem in
|
|
29
|
+
* `issues`), 304 for an unstable structure
|
|
30
|
+
*/
|
|
31
|
+
export const createFrameAnalysis = (model, options = {}) => {
|
|
32
|
+
const issues = validateFrameModel(model);
|
|
33
|
+
if (issues.length > 0)
|
|
34
|
+
throwIssues(issues);
|
|
35
|
+
const system = prepareFrameSystem(model);
|
|
36
|
+
const combinations = model.combinations ?? [];
|
|
37
|
+
const resolved = resolveCombinations(combinations, new Set(model.loadCases.map((c) => c.id)));
|
|
38
|
+
const withStations = (options.diagrams ?? "full") === "full";
|
|
39
|
+
const states = new Map();
|
|
40
|
+
const cases = {};
|
|
41
|
+
const nodalByCase = groupByCase(model.nodalLoads);
|
|
42
|
+
const memberByCase = groupByCase(model.memberLoads);
|
|
43
|
+
for (const loadCase of model.loadCases) {
|
|
44
|
+
const state = solveLoadCase(system, loadCase, {
|
|
45
|
+
nodalLoads: nodalByCase.get(loadCase.id) ?? [],
|
|
46
|
+
memberLoads: memberByCase.get(loadCase.id) ?? [],
|
|
47
|
+
});
|
|
48
|
+
states.set(loadCase.id, state);
|
|
49
|
+
cases[loadCase.id] = presentState(system, state, { id: loadCase.id, kind: "case", name: loadCase.name, type: loadCase.type }, { stations: options.stations, withStations });
|
|
50
|
+
}
|
|
51
|
+
const combinationStates = new Map();
|
|
52
|
+
const combinationResults = {};
|
|
53
|
+
for (const combination of combinations) {
|
|
54
|
+
// Non-empty: validation rejects combinations without terms
|
|
55
|
+
const terms = [...resolved.get(combination.id)].map(([caseId, factor]) => ({ state: states.get(caseId), factor }));
|
|
56
|
+
const state = combineStates(terms);
|
|
57
|
+
combinationStates.set(combination.id, state);
|
|
58
|
+
combinationResults[combination.id] = presentState(system, state, { id: combination.id, kind: "combination", name: combination.name }, { stations: options.stations, withStations });
|
|
59
|
+
}
|
|
60
|
+
const warnings = [
|
|
61
|
+
...Object.values(cases),
|
|
62
|
+
...Object.values(combinationResults),
|
|
63
|
+
].flatMap((r) => r.warnings.map((w) => ({
|
|
64
|
+
...w,
|
|
65
|
+
message: `${r.kind === "case" ? "Load case" : "Load combination"} "${r.id}": ${w.message}`,
|
|
66
|
+
})));
|
|
67
|
+
const combinationList = combinations.map((c) => combinationResults[c.id]);
|
|
68
|
+
const result = {
|
|
69
|
+
cases,
|
|
70
|
+
combinations: combinationResults,
|
|
71
|
+
envelope: combinationList.length > 0 ? buildEnvelope(combinationList) : undefined,
|
|
72
|
+
calculationDetails: {
|
|
73
|
+
nodeCount: system.nodes.length,
|
|
74
|
+
memberCount: system.members.length,
|
|
75
|
+
dofCount: system.dofCount,
|
|
76
|
+
freeDofCount: system.free.length,
|
|
77
|
+
profileSize: system.profileSize,
|
|
78
|
+
loadCaseCount: model.loadCases.length,
|
|
79
|
+
combinationCount: combinations.length,
|
|
80
|
+
},
|
|
81
|
+
units: { force: "kN", moment: "kN·m", length: "mm", rotation: "rad" },
|
|
82
|
+
warnings,
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
result,
|
|
86
|
+
memberDiagram: (resultId, memberId, stations) => {
|
|
87
|
+
const state = combinationStates.get(resultId) ?? states.get(resultId);
|
|
88
|
+
if (!state)
|
|
89
|
+
throw new Error(`Load case or combination "${resultId}" is not in the model.`);
|
|
90
|
+
const m = system.memberIndex.get(memberId);
|
|
91
|
+
if (m === undefined)
|
|
92
|
+
throw new Error(`Member ${String(memberId)} is not in the model.`);
|
|
93
|
+
return presentMemberDiagram(system, state, m, stations ?? options.stations);
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Analyses a 3D frame by the direct stiffness method (linear elastic, small displacements)
|
|
99
|
+
* for every load case, then forms every load combination by superposition.
|
|
100
|
+
*
|
|
101
|
+
* The model is validated first (`validateFrameModel`). The stiffness matrix is assembled once
|
|
102
|
+
* in skyline storage with the nodes in reverse Cuthill–McKee order and factorised once; each
|
|
103
|
+
* load case is a separate solve. A combination is the factored sum of its load cases (nested
|
|
104
|
+
* combinations are expanded), and its member diagrams are rebuilt from the combined end forces
|
|
105
|
+
* and factored member loads, so their extremes are exact rather than sums of case extremes.
|
|
106
|
+
*
|
|
107
|
+
* Units: node coordinates, section properties and positions in mm and MPa; loads in kN, kN·m
|
|
108
|
+
* and kN/m; springs in kN/mm and kN·m/rad; unit weight in kN/m³. Results are in kN, kN·m, mm
|
|
109
|
+
* and rad. Global axes X, Y, Z are right-handed with Z up; members use ETABS-style local axes
|
|
110
|
+
* 1, 2, 3 (see `memberAxes`). Member end forces and diagrams use right-hand rotations.
|
|
111
|
+
*
|
|
112
|
+
* Model and result are plain data (JSON-serialisable), so the analysis can run in a Web Worker.
|
|
113
|
+
*
|
|
114
|
+
* @param model - Nodes, members, restraints, load cases, loads tagged with their load case,
|
|
115
|
+
* and combinations
|
|
116
|
+
* @param options - Diagram station count and detail
|
|
117
|
+
* @returns `cases` and `combinations` keyed by id, `envelope` over the combinations,
|
|
118
|
+
* `calculationDetails`, `units` and `warnings`
|
|
119
|
+
* @throws {FrameAnalysisError} 301–314 for an invalid model (with `details` and every problem in
|
|
120
|
+
* `issues`), 304 for an unstable structure
|
|
121
|
+
*/
|
|
122
|
+
export const analyzeFrame = (model, options = {}) => createFrameAnalysis(model, options).result;
|
|
123
|
+
//# sourceMappingURL=analyze-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-frame.js","sourceRoot":"","sources":["../../../../../src/fea/frame/solver/analyze-frame.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const DOF_KEYS = ["ux", "uy", "uz", "rx", "ry", "rz"];
|
|
2
|
+
/** Spring stiffness unit conversion: kN/mm → N/mm, kN·m/rad → N·mm/rad. */
|
|
3
|
+
const SPRING_FACTOR = [1e3, 1e3, 1e3, 1e6, 1e6, 1e6];
|
|
4
|
+
const parse = (value, factor) => {
|
|
5
|
+
if (value === true)
|
|
6
|
+
return { fixed: true, spring: 0 };
|
|
7
|
+
if (typeof value === "number" && value > 0)
|
|
8
|
+
return { fixed: false, spring: value * factor };
|
|
9
|
+
return { fixed: false, spring: 0 };
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Collects restraints into per-DOF fixed flags and spring stiffnesses.
|
|
13
|
+
*
|
|
14
|
+
* @param restraints - Model restraints
|
|
15
|
+
* @param nodeIndex - Map from node id to node index (6 DOFs per node)
|
|
16
|
+
* @param dofCount - Total number of global DOFs
|
|
17
|
+
*/
|
|
18
|
+
export const buildBoundaryConditions = (restraints, nodeIndex, dofCount) => {
|
|
19
|
+
const fixed = new Array(dofCount).fill(false);
|
|
20
|
+
const spring = new Array(dofCount).fill(0);
|
|
21
|
+
for (const restraint of restraints) {
|
|
22
|
+
const base = 6 * nodeIndex.get(restraint.nodeId);
|
|
23
|
+
DOF_KEYS.forEach((key, k) => {
|
|
24
|
+
const parsed = parse(restraint[key], SPRING_FACTOR[k]);
|
|
25
|
+
if (parsed.fixed)
|
|
26
|
+
fixed[base + k] = true;
|
|
27
|
+
spring[base + k] = parsed.spring;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const restrained = fixed.map((f, i) => f || spring[i] > 0);
|
|
31
|
+
return { fixed, spring, restrained };
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=boundary-conditions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundary-conditions.js","sourceRoot":"","sources":["../../../../../src/fea/frame/solver/boundary-conditions.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAE/D,2EAA2E;AAC3E,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAQrD,MAAM,KAAK,GAAG,CACZ,KAA+B,EAC/B,MAAc,EACsB,EAAE;IACtC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;IAC5F,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AACrC,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,UAAuB,EACvB,SAA2C,EAC3C,QAAgB,EACI,EAAE;IACtB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAU,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,KAAK,CAAS,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,CAAC,GAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAY,CAAC;QAC7D,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YACvD,IAAI,MAAM,CAAC,KAAK;gBAAE,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;YACzC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACvC,CAAC,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { FrameAnalysisError, FrameErrors } from "../../../core/errors/frame-analysis.error.js";
|
|
2
|
+
/**
|
|
3
|
+
* Expands every combination into net factors on load cases, following nested combinations.
|
|
4
|
+
*
|
|
5
|
+
* @param combinations - Model combinations
|
|
6
|
+
* @param caseIds - Ids of the model's load cases
|
|
7
|
+
* @returns For each combination id, the net factor on each load case it uses
|
|
8
|
+
* @throws {FrameAnalysisError} 309 for an unknown or missing reference, 310 for a loop,
|
|
9
|
+
* 311 for a non-finite factor or an empty combination
|
|
10
|
+
*/
|
|
11
|
+
export const resolveCombinations = (combinations, caseIds) => {
|
|
12
|
+
const byId = new Map(combinations.map((c) => [c.id, c]));
|
|
13
|
+
for (const combination of combinations) {
|
|
14
|
+
if (!Array.isArray(combination.terms) || combination.terms.length === 0) {
|
|
15
|
+
throw new FrameAnalysisError(FrameErrors.INVALID_LOAD_FACTOR, {
|
|
16
|
+
combinationId: combination.id,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
for (const term of combination.terms) {
|
|
20
|
+
if (!Number.isFinite(term.factor))
|
|
21
|
+
throw new FrameAnalysisError(FrameErrors.INVALID_LOAD_FACTOR, {
|
|
22
|
+
combinationId: combination.id,
|
|
23
|
+
});
|
|
24
|
+
const isCase = "case" in term && term.case !== undefined;
|
|
25
|
+
const isCombination = "combination" in term && term.combination !== undefined;
|
|
26
|
+
if (isCase === isCombination)
|
|
27
|
+
throw new FrameAnalysisError(FrameErrors.UNKNOWN_LOAD_CASE, {
|
|
28
|
+
combinationId: combination.id,
|
|
29
|
+
});
|
|
30
|
+
if (isCase && !caseIds.has(term.case)) {
|
|
31
|
+
throw new FrameAnalysisError(FrameErrors.UNKNOWN_LOAD_CASE, {
|
|
32
|
+
combinationId: combination.id,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (isCombination && !byId.has(term.combination)) {
|
|
36
|
+
throw new FrameAnalysisError(FrameErrors.UNKNOWN_LOAD_CASE, {
|
|
37
|
+
combinationId: combination.id,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const resolved = new Map();
|
|
43
|
+
const visiting = new Set();
|
|
44
|
+
const resolve = (id) => {
|
|
45
|
+
const done = resolved.get(id);
|
|
46
|
+
if (done)
|
|
47
|
+
return done;
|
|
48
|
+
if (visiting.has(id)) {
|
|
49
|
+
throw new FrameAnalysisError(FrameErrors.CIRCULAR_COMBINATION, { combinationId: id });
|
|
50
|
+
}
|
|
51
|
+
visiting.add(id);
|
|
52
|
+
const factors = new Map();
|
|
53
|
+
const addFactor = (caseId, factor) => factors.set(caseId, (factors.get(caseId) ?? 0) + factor);
|
|
54
|
+
for (const term of byId.get(id).terms) {
|
|
55
|
+
if ("case" in term) {
|
|
56
|
+
addFactor(term.case, term.factor);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
resolve(term.combination).forEach((f, caseId) => addFactor(caseId, term.factor * f));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
visiting.delete(id);
|
|
63
|
+
resolved.set(id, factors);
|
|
64
|
+
return factors;
|
|
65
|
+
};
|
|
66
|
+
combinations.forEach((c) => resolve(c.id));
|
|
67
|
+
return resolved;
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=combinations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combinations.js","sourceRoot":"","sources":["../../../../../src/fea/frame/solver/combinations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { SINGULARITY_TOLERANCE } from "../../../core/constants/frame.constant.js";
|
|
2
|
+
import { FrameErrors } from "../../../core/errors/frame-analysis.error.js";
|
|
3
|
+
import { createSkyline, reverseCuthillMcKee, skylineAdd, skylineFactor, skylineSize, } from "../../../utils/skyline.js";
|
|
4
|
+
import { beam3dLocalStiffnessRightHanded } from "../elements/beam-3d-stiffness.js";
|
|
5
|
+
import { condenseMember } from "../elements/static-condensation.js";
|
|
6
|
+
import { memberAxes, transformationMatrix } from "../transformation/coordinate-transform.js";
|
|
7
|
+
import { frameIssue, throwIssues } from "../validation/validate-model.js";
|
|
8
|
+
import { buildBoundaryConditions } from "./boundary-conditions.js";
|
|
9
|
+
import { memberDofs, memberGlobalStiffness } from "./global-assembly.js";
|
|
10
|
+
const RELEASE_KEYS = ["u1", "u2", "u3", "r1", "r2", "r3"];
|
|
11
|
+
const DOF_NAMES = ["ux", "uy", "uz", "rx", "ry", "rz"];
|
|
12
|
+
const releasedIndices = (release, offset) => RELEASE_KEYS.flatMap((key, k) => (release?.[key] ? [offset + k] : []));
|
|
13
|
+
/**
|
|
14
|
+
* Builds the member matrices of a model that passed `validateFrameModel`, assembles the free
|
|
15
|
+
* stiffness in skyline storage with nodes in reverse Cuthill–McKee order, and factorises it
|
|
16
|
+
* once for all load cases.
|
|
17
|
+
*
|
|
18
|
+
* @throws {FrameAnalysisError} 304 if the structure is a mechanism; `details` names a node and
|
|
19
|
+
* a DOF involved in it
|
|
20
|
+
*/
|
|
21
|
+
export const prepareFrameSystem = (model) => {
|
|
22
|
+
const { nodes, members, restraints } = model;
|
|
23
|
+
const nodeIndex = new Map(nodes.map((n, i) => [n.id, i]));
|
|
24
|
+
const memberIndex = new Map(members.map((m, i) => [m.id, i]));
|
|
25
|
+
const dofCount = 6 * nodes.length;
|
|
26
|
+
const boundary = buildBoundaryConditions(restraints, nodeIndex, dofCount);
|
|
27
|
+
const systemMembers = members.map((member) => {
|
|
28
|
+
const start = nodes[nodeIndex.get(member.startNodeId)];
|
|
29
|
+
const end = nodes[nodeIndex.get(member.endNodeId)];
|
|
30
|
+
const { length, lambda } = memberAxes([start.x, start.y, start.z], [end.x, end.y, end.z], member.angle ?? 0);
|
|
31
|
+
const { E, G, A, I22, I33, J } = member.section;
|
|
32
|
+
const releasedDofs = [
|
|
33
|
+
...releasedIndices(member.releases?.start, 0),
|
|
34
|
+
...releasedIndices(member.releases?.end, 6),
|
|
35
|
+
];
|
|
36
|
+
const condensed = condenseMember(beam3dLocalStiffnessRightHanded(E, G, A, I22, I33, J, length), releasedDofs);
|
|
37
|
+
return {
|
|
38
|
+
id: member.id,
|
|
39
|
+
section: member.section,
|
|
40
|
+
startIndex: nodeIndex.get(member.startNodeId),
|
|
41
|
+
endIndex: nodeIndex.get(member.endNodeId),
|
|
42
|
+
T: transformationMatrix(lambda),
|
|
43
|
+
k: condensed.k,
|
|
44
|
+
condenseFixedEndForces: condensed.condenseFixedEndForces,
|
|
45
|
+
released: Array.from({ length: 12 }, (_, i) => releasedDofs.includes(i)),
|
|
46
|
+
length,
|
|
47
|
+
lambda,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
// ---- Equation numbering: nodes in RCM order, fixed DOFs skipped ------------------
|
|
51
|
+
const adjacency = nodes.map(() => []);
|
|
52
|
+
for (const m of systemMembers) {
|
|
53
|
+
adjacency[m.startIndex].push(m.endIndex);
|
|
54
|
+
adjacency[m.endIndex].push(m.startIndex);
|
|
55
|
+
}
|
|
56
|
+
const equation = new Int32Array(dofCount).fill(-1);
|
|
57
|
+
const free = [];
|
|
58
|
+
for (const node of reverseCuthillMcKee(adjacency)) {
|
|
59
|
+
for (let k = 0; k < 6; k++) {
|
|
60
|
+
const dof = 6 * node + k;
|
|
61
|
+
if (!boundary.fixed[dof]) {
|
|
62
|
+
equation[dof] = free.length;
|
|
63
|
+
free.push(dof);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// ---- Profile, assembly and factorisation -----------------------------------------
|
|
68
|
+
let factor = null;
|
|
69
|
+
if (free.length > 0) {
|
|
70
|
+
const first = free.map((_, e) => e);
|
|
71
|
+
const memberEquations = systemMembers.map((m) => memberDofs(m).map((d) => equation[d]));
|
|
72
|
+
for (const eqs of memberEquations) {
|
|
73
|
+
const active = eqs.filter((e) => e >= 0);
|
|
74
|
+
const low = Math.min(...active);
|
|
75
|
+
for (const e of active)
|
|
76
|
+
if (low < first[e])
|
|
77
|
+
first[e] = low;
|
|
78
|
+
}
|
|
79
|
+
const K = createSkyline(first);
|
|
80
|
+
systemMembers.forEach((m, index) => {
|
|
81
|
+
const kGlobal = memberGlobalStiffness(m);
|
|
82
|
+
const eqs = memberEquations[index];
|
|
83
|
+
// a member's 12 DOFs are distinct, so each unordered pair and each diagonal is added once
|
|
84
|
+
for (let a = 0; a < 12; a++) {
|
|
85
|
+
if (eqs[a] < 0)
|
|
86
|
+
continue;
|
|
87
|
+
for (let b = 0; b < 12; b++) {
|
|
88
|
+
if (eqs[b] >= eqs[a])
|
|
89
|
+
skylineAdd(K, eqs[a], eqs[b], kGlobal[a][b]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
free.forEach((dof, e) => {
|
|
94
|
+
if (boundary.spring[dof] > 0)
|
|
95
|
+
skylineAdd(K, e, e, boundary.spring[dof]);
|
|
96
|
+
});
|
|
97
|
+
const result = skylineFactor(K, SINGULARITY_TOLERANCE);
|
|
98
|
+
if (!result.ok) {
|
|
99
|
+
const dof = free[result.failedPivot];
|
|
100
|
+
throwIssues([
|
|
101
|
+
frameIssue(FrameErrors.STRUCTURE_UNSTABLE, {
|
|
102
|
+
nodeId: nodes[Math.floor(dof / 6)].id,
|
|
103
|
+
dof: DOF_NAMES[dof % 6],
|
|
104
|
+
}),
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
factor = K;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
nodes,
|
|
111
|
+
nodeIndex,
|
|
112
|
+
memberIndex,
|
|
113
|
+
members: systemMembers,
|
|
114
|
+
dofCount,
|
|
115
|
+
boundary,
|
|
116
|
+
equation,
|
|
117
|
+
free,
|
|
118
|
+
factor,
|
|
119
|
+
profileSize: factor ? skylineSize(factor) : 0,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=frame-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-system.js","sourceRoot":"","sources":["../../../../../src/fea/frame/solver/frame-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { matMul, transpose } from "../../../utils/matrix.js";
|
|
2
|
+
/** Global DOF numbers (6 per node) of a member's 12 end DOFs. */
|
|
3
|
+
export const memberDofs = (member) => {
|
|
4
|
+
const dofs = [];
|
|
5
|
+
for (const node of [member.startIndex, member.endIndex]) {
|
|
6
|
+
for (let k = 0; k < 6; k++)
|
|
7
|
+
dofs.push(6 * node + k);
|
|
8
|
+
}
|
|
9
|
+
return dofs;
|
|
10
|
+
};
|
|
11
|
+
/** A member's stiffness in global axes, `Tᵀ·k·T` (N and mm). */
|
|
12
|
+
export const memberGlobalStiffness = (member) => matMul(transpose(member.T), matMul(member.k, member.T));
|
|
13
|
+
/**
|
|
14
|
+
* Adds `sign · Tᵀ·f` of one member's local end-force vector to a global vector (N and N·mm).
|
|
15
|
+
* With `sign = −1` and fixed-end forces this adds the equivalent nodal loads; with `sign = +1`
|
|
16
|
+
* and `k·u` it adds the member's elastic end forces.
|
|
17
|
+
*/
|
|
18
|
+
export const scatterMemberForces = (target, member, localForces, sign) => {
|
|
19
|
+
const dofs = memberDofs(member);
|
|
20
|
+
for (let a = 0; a < 12; a++) {
|
|
21
|
+
let value = 0;
|
|
22
|
+
for (let j = 0; j < 12; j++)
|
|
23
|
+
value += member.T[j][a] * localForces[j];
|
|
24
|
+
target[dofs[a]] += sign * value;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=global-assembly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-assembly.js","sourceRoot":"","sources":["../../../../../src/fea/frame/solver/global-assembly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAe,MAAM,mBAAmB,CAAC;AASnE,iEAAiE;AACjE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAuD,EAAY,EAAE;IAC9F,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,gEAAgE;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAsB,EAAU,EAAE,CACtE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAgB,EAChB,MAA6D,EAC7D,WAAqB,EACrB,IAAY,EACN,EAAE;IACR,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;YAAE,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QACtE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,KAAK,CAAC;IAClC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { FrameAnalysisError, FrameErrors } from "../../../core/errors/frame-analysis.error.js";
|
|
2
|
+
import { matVec } from "../../../utils/matrix.js";
|
|
3
|
+
import { skylineSolve } from "../../../utils/skyline.js";
|
|
4
|
+
import { fixedEndForces } from "../elements/fixed-end-forces.js";
|
|
5
|
+
import { memberDofs, scatterMemberForces } from "./global-assembly.js";
|
|
6
|
+
const GLOBAL_DIRECTIONS = {
|
|
7
|
+
X: [1, 0, 0],
|
|
8
|
+
Y: [0, 1, 0],
|
|
9
|
+
Z: [0, 0, 1],
|
|
10
|
+
};
|
|
11
|
+
/** Resolves a member load into local-axis loads in N and mm. */
|
|
12
|
+
const toLocalLoads = (load, lambda, L) => {
|
|
13
|
+
const components = (direction) => {
|
|
14
|
+
if (direction === "1" || direction === "2" || direction === "3") {
|
|
15
|
+
return [{ axis: Number(direction), factor: 1 }];
|
|
16
|
+
}
|
|
17
|
+
const v = GLOBAL_DIRECTIONS[direction];
|
|
18
|
+
return [1, 2, 3]
|
|
19
|
+
.map((axis) => ({
|
|
20
|
+
axis,
|
|
21
|
+
factor: lambda[axis - 1][0] * v[0] + lambda[axis - 1][1] * v[1] + lambda[axis - 1][2] * v[2],
|
|
22
|
+
}))
|
|
23
|
+
.filter((c) => Math.abs(c.factor) > 1e-12);
|
|
24
|
+
};
|
|
25
|
+
return components(load.direction).map(({ axis, factor }) => load.type === "udl"
|
|
26
|
+
? {
|
|
27
|
+
type: "udl",
|
|
28
|
+
axis,
|
|
29
|
+
w: load.w * factor, // kN/m = N/mm
|
|
30
|
+
start: load.start ?? 0,
|
|
31
|
+
end: load.end ?? L,
|
|
32
|
+
}
|
|
33
|
+
: { type: "point", axis, P: load.P * factor * 1e3, a: load.a });
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Solves one load case against the prepared, factorised system.
|
|
37
|
+
*
|
|
38
|
+
* Self-weight is `selfWeight · unitWeight · A` per unit member length along global −Z.
|
|
39
|
+
*
|
|
40
|
+
* @param loadCase - The load case (id and self-weight multiplier)
|
|
41
|
+
* @param loads - The nodal and member loads tagged with this load case
|
|
42
|
+
*
|
|
43
|
+
* @throws {FrameAnalysisError} 308 for a load outside its member, 313 if self-weight is
|
|
44
|
+
* requested for a member without `unitWeight`
|
|
45
|
+
*/
|
|
46
|
+
export const solveLoadCase = (system, loadCase, loads) => {
|
|
47
|
+
const { members, dofCount, boundary, equation, free, factor, nodeIndex, memberIndex } = system;
|
|
48
|
+
const F = new Array(dofCount).fill(0);
|
|
49
|
+
const loadsByMember = members.map(() => []);
|
|
50
|
+
for (const load of loads.memberLoads) {
|
|
51
|
+
loadsByMember[memberIndex.get(load.memberId)].push(load);
|
|
52
|
+
}
|
|
53
|
+
const selfWeight = loadCase.selfWeight ?? 0;
|
|
54
|
+
const memberLoads = members.map((member, m) => {
|
|
55
|
+
const memberLoadsHere = [...loadsByMember[m]];
|
|
56
|
+
if (selfWeight !== 0) {
|
|
57
|
+
const { unitWeight, A } = member.section;
|
|
58
|
+
if (unitWeight === undefined)
|
|
59
|
+
throw new FrameAnalysisError(FrameErrors.MISSING_UNIT_WEIGHT);
|
|
60
|
+
// kN/m³ · m² = kN/m
|
|
61
|
+
const w = -selfWeight * unitWeight * A * 1e-6;
|
|
62
|
+
if (w !== 0) {
|
|
63
|
+
memberLoadsHere.push({
|
|
64
|
+
loadCase: loadCase.id,
|
|
65
|
+
type: "udl",
|
|
66
|
+
memberId: member.id,
|
|
67
|
+
direction: "Z",
|
|
68
|
+
w,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return memberLoadsHere.flatMap((load) => toLocalLoads(load, member.lambda, member.length));
|
|
73
|
+
});
|
|
74
|
+
const fixed = members.map((member, m) => {
|
|
75
|
+
const condensed = member.condenseFixedEndForces(fixedEndForces(memberLoads[m], member.length));
|
|
76
|
+
scatterMemberForces(F, member, condensed, -1);
|
|
77
|
+
return condensed;
|
|
78
|
+
});
|
|
79
|
+
for (const load of loads.nodalLoads) {
|
|
80
|
+
const base = 6 * nodeIndex.get(load.nodeId);
|
|
81
|
+
[load.fx, load.fy, load.fz].forEach((v, k) => (F[base + k] += (v ?? 0) * 1e3));
|
|
82
|
+
[load.mx, load.my, load.mz].forEach((v, k) => (F[base + 3 + k] += (v ?? 0) * 1e6));
|
|
83
|
+
}
|
|
84
|
+
const U = new Array(dofCount).fill(0);
|
|
85
|
+
if (factor) {
|
|
86
|
+
const solution = skylineSolve(factor, free.map((dof) => F[dof]));
|
|
87
|
+
free.forEach((dof) => (U[dof] = solution[equation[dof]]));
|
|
88
|
+
}
|
|
89
|
+
// Elastic end forces k·u per member; their global sum is K·U, from which R = K·U − F
|
|
90
|
+
const KU = new Array(dofCount).fill(0);
|
|
91
|
+
const memberForces = members.map((member, m) => {
|
|
92
|
+
const uLocal = matVec(member.T, memberDofs(member).map((d) => U[d]));
|
|
93
|
+
const elastic = matVec(member.k, uLocal);
|
|
94
|
+
scatterMemberForces(KU, member, elastic, 1);
|
|
95
|
+
return elastic.map((v, i) => v + fixed[m][i]);
|
|
96
|
+
});
|
|
97
|
+
const R = KU.map((v, i) => (boundary.restrained[i] ? v - F[i] : 0));
|
|
98
|
+
return { U, R, F, memberForces, memberLoads };
|
|
99
|
+
};
|
|
100
|
+
const scaleLoad = (load, factor) => load.type === "udl" ? { ...load, w: load.w * factor } : { ...load, P: load.P * factor };
|
|
101
|
+
/** Superposes factored states: `Σ factor × state`. Member loads are concatenated, scaled. */
|
|
102
|
+
export const combineStates = (terms) => {
|
|
103
|
+
const first = terms[0].state;
|
|
104
|
+
const add = (pick, length) => {
|
|
105
|
+
const out = new Array(length).fill(0);
|
|
106
|
+
for (const { state, factor } of terms) {
|
|
107
|
+
pick(state).forEach((v, i) => (out[i] += factor * v));
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
U: add((s) => s.U, first.U.length),
|
|
113
|
+
R: add((s) => s.R, first.R.length),
|
|
114
|
+
F: add((s) => s.F, first.F.length),
|
|
115
|
+
memberForces: first.memberForces.map((_, m) => add((s) => s.memberForces[m], 12)),
|
|
116
|
+
memberLoads: first.memberLoads.map((_, m) => terms.flatMap(({ state, factor }) => factor === 0 ? [] : state.memberLoads[m].map((l) => scaleLoad(l, factor)))),
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=load-case-solver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-case-solver.js","sourceRoot":"","sources":["../../../../../src/fea/frame/solver/load-case-solver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { VERTICAL_MEMBER_TOLERANCE } from "../../../core/constants/frame.constant.js";
|
|
2
|
+
import { FrameAnalysisError, FrameErrors } from "../../../core/errors/frame-analysis.error.js";
|
|
3
|
+
import { zeros } from "../../../utils/matrix.js";
|
|
4
|
+
const cross = (a, b) => [
|
|
5
|
+
a[1] * b[2] - a[2] * b[1],
|
|
6
|
+
a[2] * b[0] - a[0] * b[2],
|
|
7
|
+
a[0] * b[1] - a[1] * b[0],
|
|
8
|
+
];
|
|
9
|
+
const norm = (a) => Math.hypot(a[0], a[1], a[2]);
|
|
10
|
+
const scale = (a, s) => [a[0] * s, a[1] * s, a[2] * s];
|
|
11
|
+
/**
|
|
12
|
+
* ETABS-style local axes of a member as the rows of a 3×3 direction-cosine matrix.
|
|
13
|
+
*
|
|
14
|
+
* Local 1 runs from the start to the end node. For a non-vertical member local 3 is
|
|
15
|
+
* horizontal (`1 × Z`) and local 2 lies in the vertical plane pointing up; for a vertical
|
|
16
|
+
* member local 2 is global +X and local 3 is `1 × 2`. `angle` then rotates local 2 and 3
|
|
17
|
+
* about local 1 by the right-hand rule.
|
|
18
|
+
*
|
|
19
|
+
* @param start - Start node coordinates in mm
|
|
20
|
+
* @param end - End node coordinates in mm
|
|
21
|
+
* @param angle - Member angle in rad (default 0)
|
|
22
|
+
* @returns `{ length, lambda }` with `lambda` rows = local 1, 2, 3 in global components
|
|
23
|
+
* @throws {FrameAnalysisError} 301 if the nodes coincide
|
|
24
|
+
*/
|
|
25
|
+
export const memberAxes = (start, end, angle = 0) => {
|
|
26
|
+
const d = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
|
|
27
|
+
const length = norm(d);
|
|
28
|
+
if (!(length > 0))
|
|
29
|
+
throw new FrameAnalysisError(FrameErrors.ZERO_LENGTH_MEMBER);
|
|
30
|
+
const e1 = scale(d, 1 / length);
|
|
31
|
+
let e2;
|
|
32
|
+
let e3;
|
|
33
|
+
if (Math.hypot(e1[0], e1[1]) < VERTICAL_MEMBER_TOLERANCE) {
|
|
34
|
+
e2 = [1, 0, 0];
|
|
35
|
+
e3 = cross(e1, e2);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const c = cross(e1, [0, 0, 1]);
|
|
39
|
+
e3 = scale(c, 1 / norm(c));
|
|
40
|
+
e2 = cross(e3, e1);
|
|
41
|
+
}
|
|
42
|
+
if (angle !== 0) {
|
|
43
|
+
const cos = Math.cos(angle);
|
|
44
|
+
const sin = Math.sin(angle);
|
|
45
|
+
const r2 = [
|
|
46
|
+
cos * e2[0] + sin * e3[0],
|
|
47
|
+
cos * e2[1] + sin * e3[1],
|
|
48
|
+
cos * e2[2] + sin * e3[2],
|
|
49
|
+
];
|
|
50
|
+
const r3 = [
|
|
51
|
+
-sin * e2[0] + cos * e3[0],
|
|
52
|
+
-sin * e2[1] + cos * e3[1],
|
|
53
|
+
-sin * e2[2] + cos * e3[2],
|
|
54
|
+
];
|
|
55
|
+
e2 = r2;
|
|
56
|
+
e3 = r3;
|
|
57
|
+
}
|
|
58
|
+
return { length, lambda: [e1, e2, e3] };
|
|
59
|
+
};
|
|
60
|
+
/** Builds the 12×12 transformation `T` (global → local) from the 3×3 direction cosines. */
|
|
61
|
+
export const transformationMatrix = (lambda) => {
|
|
62
|
+
const T = zeros(12, 12);
|
|
63
|
+
for (let block = 0; block < 4; block++) {
|
|
64
|
+
for (let i = 0; i < 3; i++) {
|
|
65
|
+
for (let j = 0; j < 3; j++)
|
|
66
|
+
T[3 * block + i][3 * block + j] = lambda[i][j];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return T;
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=coordinate-transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinate-transform.js","sourceRoot":"","sources":["../../../../../src/fea/frame/transformation/coordinate-transform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.type.js","sourceRoot":"","sources":["../../../../../src/fea/frame/types/model.type.ts"],"names":[],"mappings":""}
|