Skip to content

Commit 6d926bc

Browse files
Add 1D Euler-Bernoulli beam solver (cubic Hermite elements) (#86)
Co-authored-by: nikoscham <nikoscham@gmail.com>
1 parent 57d94ff commit 6d926bc

18 files changed

Lines changed: 1038 additions & 92 deletions

‎dist/feascript-worker.esm.js‎

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript-worker.esm.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript.cjs.js‎

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript.cjs.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript.esm.js‎

Lines changed: 22 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript.esm.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript.umd.js‎

Lines changed: 29 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/feascript.umd.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* ════════════════════════════════════════════════════════════════
3+
* FEAScript Core Library
4+
* Lightweight Finite Element Simulation in JavaScript
5+
* Version: 0.3.0 (RC) | https://feascript.com
6+
* MIT License © 2023–2026 FEAScript
7+
* ════════════════════════════════════════════════════════════════
8+
*/
9+
10+
/**
11+
* Clamped and spring-supported Euler-Bernoulli beam
12+
*
13+
* Reproduces the "Bending of a Beam" example from J.N. Reddy, "An Introduction to
14+
* the Finite Element Method", 3rd ed., McGraw-Hill, 2006 (FEM1D example problems,
15+
* Chapter 7), solved there with the reference FEM1D Fortran program (MODEL=3,
16+
* NTYPE=0, IELEM=0 i.e. Hermite cubic elements).
17+
*
18+
* Geometry: a 10 m beam, clamped at x=0, resting on a roller at midspan (x=5 m),
19+
* and connected to a linear transverse spring at the free end (x=10 m).
20+
* Mesh: 2 Hermite cubic beam elements of 5 m each -> 3 nodes: [1, 2, 3]
21+
*
22+
* 1,000 N/m (on 0 <= x <= 5) 2,500 N (down, at node 3)
23+
* v v v v v v v v v v |
24+
* /////|--------------------|-------------------| ~~~~ spring, k = 1e-4*EI
25+
* ///// 1 (clamped) 2 (roller) 3 (free end, spring)
26+
* |<-------- 5 m ----->|<------- 5 m ------>|
27+
* ^ moment 1,250 N-m applied at node 2
28+
*
29+
* EI = 2e6 N-m^2 (constant), k_spring = 1e-4 * EI = 200 N/m
30+
*
31+
* Boundary conditions (see beamBoundaryConditions.js for the condition syntax):
32+
* - Node 1 (x=0): fixed -> w=0, theta=0 (clamped support)
33+
* - Node 2 (x=5): pinned + moment -> w=0, applied moment M=1250 N-m
34+
* - Node 3 (x=10): spring + force -> k=200 N/m, applied point load P=-2500 N
35+
*/
36+
37+
// Import Math.js
38+
import * as math from "mathjs";
39+
global.math = math;
40+
41+
// Import FEAScript library
42+
import { FEAScriptModel, printVersion } from "feascript";
43+
44+
console.log("FEAScript Version:", printVersion);
45+
46+
// Create a new FEAScript model
47+
const model = new FEAScriptModel();
48+
49+
// Select physics/PDE
50+
model.setModelConfig("eulerBernoulliBeamScript", {
51+
coefficientFunctions: {
52+
EI: (x) => 2.0e6, // Bending stiffness E*I (N-m^2), constant along the beam
53+
// Distributed transverse load: -1,000 N/m over the first (clamped) span only
54+
q: (x) => (x <= 5 ? -1000 : 0),
55+
// c0 defaults to 0 (no elastic foundation) when omitted
56+
},
57+
});
58+
59+
// Define mesh configuration
60+
// elementOrder is 'linear' because that only describes the 2-node beam geometry;
61+
// the field itself is always interpolated with cubic Hermite shape functions internally
62+
model.setMeshConfig({
63+
meshDimension: "1D",
64+
elementOrder: "linear",
65+
numElementsX: 2,
66+
maxX: 10,
67+
});
68+
69+
// Define boundary conditions (keyed by 1-based global node number)
70+
model.addBoundaryCondition("1", [["fixed"]]); // Clamped support
71+
model.addBoundaryCondition("2", [["pinned"], ["moment", 1250]]); // Roller + applied moment
72+
model.addBoundaryCondition("3", [["spring", 200], ["force", -2500]]); // Spring support + point load
73+
74+
// Set solver method
75+
model.setSolverMethod("lusolve");
76+
77+
// Solve the problem
78+
const { solutionVector } = model.solve();
79+
80+
// The solution vector is ordered [w_0, theta_0, w_1, theta_1, w_2, theta_2, ...]
81+
// (mathjs' lusolve returns a nested array, so flatten defensively before reading it)
82+
const flatSolution = solutionVector.map((entry) => (Array.isArray(entry) ? entry[0] : entry));
83+
84+
const nodeXCoordinates = [0, 5, 10];
85+
console.log("\nNode | x (m) | Deflection w (m) | Rotation theta (rad)");
86+
console.log("-----|----------|-------------------|----------------------");
87+
for (let nodeIndex = 0; nodeIndex < nodeXCoordinates.length; nodeIndex++) {
88+
const w = flatSolution[2 * nodeIndex];
89+
const theta = flatSolution[2 * nodeIndex + 1];
90+
console.log(
91+
` ${nodeIndex + 1} | ${nodeXCoordinates[nodeIndex].toFixed(2).padStart(8)} | ${w
92+
.toExponential(4)
93+
.padStart(17)} | ${theta.toExponential(4).padStart(20)}`,
94+
);
95+
}

‎examples/Beam1DFEM/README.md‎

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<img src="https://feascript.github.io/FEAScript-website/assets/feascript-structural-mechanics.png" width="80" alt="FEAScript Beam1DFEM Logo">
2+
3+
# 1D Euler-Bernoulli Beam Examples
4+
5+
This directory contains Node.js examples demonstrating how to use the FEAScript library to solve
6+
1D beam bending problems with the Euler-Bernoulli beam theory, using cubic Hermite finite elements.
7+
8+
## Examples
9+
10+
#### 1. Clamped and Spring-Supported Beam (`Beam1DEuler_Bernoulli.js`)
11+
12+
Reproduces the "Bending of a Beam" example from J.N. Reddy, _An Introduction to the Finite Element
13+
Method_, 3rd ed., McGraw-Hill, 2006 (FEM1D example problems, Chapter 7). A 10 m beam is clamped at
14+
one end, supported by a roller at midspan, and connected to a linear elastic spring at the free
15+
end. It carries a uniformly distributed load over the clamped span, a concentrated moment at the
16+
roller, and a point load at the free end.
17+
18+
## Model overview
19+
20+
The 1D Euler-Bernoulli beam solver (`eulerBernoulliBeamScript`) assembles the fourth-order beam
21+
bending equation
22+
23+
```
24+
d²/dx²( EI(x) d²w/dx² ) + c0(x) w = q(x)
25+
```
26+
27+
using cubic Hermite shape functions, so that both the deflection `w` and the rotation
28+
`theta = dw/dx` are continuous across element boundaries (C¹ continuity), as required for a
29+
fourth-order (curvature-based) formulation. Each node therefore carries **2 degrees of freedom**,
30+
ordered as `[w_0, theta_0, w_1, theta_1, ...]` in the solution vector.
31+
32+
### Mesh configuration
33+
34+
The beam geometry only needs each element's 2 end nodes, so `elementOrder` should be set to
35+
`"linear"` when configuring the mesh — this describes the geometry only. The field itself is
36+
always interpolated with cubic Hermite shape functions internally, independent of this setting
37+
(a "subparametric" element formulation, standard for beam elements).
38+
39+
```javascript
40+
model.setMeshConfig({
41+
meshDimension: "1D",
42+
elementOrder: "linear",
43+
numElementsX: 2,
44+
maxX: 10,
45+
});
46+
```
47+
48+
### Coefficient functions
49+
50+
```javascript
51+
model.setModelConfig("eulerBernoulliBeamScript", {
52+
coefficientFunctions: {
53+
EI: (x) => 2.0e6, // Bending stiffness E*I(x) [required]
54+
c0: (x) => 0, // Elastic foundation modulus [optional, defaults to 0]
55+
q: (x) => -1000, // Distributed transverse load [optional, defaults to 0]
56+
},
57+
});
58+
```
59+
60+
### Boundary conditions
61+
62+
Unlike the scalar 1D models (which tag only the two ends of the domain as boundary `"0"`/`"1"`),
63+
beam problems commonly need essential and natural conditions at interior nodes as well (e.g. a
64+
midspan support, or a point load applied partway along the beam). Boundary conditions for the beam
65+
solver are therefore keyed by the **1-based global node number**, and each key maps to an **array**
66+
of condition tuples, since a node can carry more than one condition at once (e.g. a spring support
67+
plus a point load):
68+
69+
```javascript
70+
model.addBoundaryCondition("1", [["fixed"]]); // w=0, theta=0 (clamped)
71+
model.addBoundaryCondition("2", [["pinned"], ["moment", 1250]]); // w=0, plus an applied moment
72+
model.addBoundaryCondition("3", [["spring", 200], ["force", -2500]]); // elastic support, plus a point load
73+
```
74+
75+
| Condition type | Kind | Effect |
76+
| ------------------------------------ | ---------------- | ----------------------------------------------------------- |
77+
| `["fixed"]` | Essential | `w = 0` and `theta = 0` (clamped support) |
78+
| `["pinned"]` / `["deflection", v]` | Essential | `w = v` (default `v = 0`; roller/pin support) |
79+
| `["rotationFixed"]` / `["rotation", v]` | Essential | `theta = v` (default `v = 0`) |
80+
| `["force", v]` | Natural | Applies a concentrated transverse force `v` at the node |
81+
| `["moment", v]` | Natural | Applies a concentrated moment `v` at the node |
82+
| `["spring", k, uRef]` | Mixed (Robin) | Transverse elastic support of stiffness `k` about `uRef` (default `uRef = 0`) |
83+
84+
## Running the Node.js Examples
85+
86+
#### 1. Create package.json with ES module support:
87+
88+
```bash
89+
echo '{"type":"module"}' > package.json
90+
```
91+
92+
#### 2. Install dependencies:
93+
94+
```bash
95+
npm install feascript
96+
```
97+
98+
#### 3. Run the example:
99+
100+
```bash
101+
node Beam1DEuler_Bernoulli.js
102+
```

0 commit comments

Comments
 (0)