Skip to content

Commit 5b4934a

Browse files
committed
Initial commit with no history
0 parents  commit 5b4934a

File tree

10 files changed

+955
-0
lines changed

10 files changed

+955
-0
lines changed

CONTRIBUTING.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## Contributing to FEAScript
2+
3+
Thank you for your interest in contributing!</br>
4+
FEAScript is in early development with continuous addition of new features and improvements. To ensure a smooth and collaborative development process, please review and follow the guidelines.
5+
6+
## Contribution Guidelines
7+
8+
1. Search the <a href="https://github.com/FEAScript/FEAScript/wiki/Roadmap" target="_blank">project roadmap</a> to see areas where help is needed.
9+
10+
2. Respect the existing FEAScript coding style. Observe the code near your intended change and attempt to preserve that style with your modifications.
11+
12+
3. We recommend using <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a> with the <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" target="_blank">Prettier</a> plugin for automatic code formatting.
13+
14+
4. Ensure that you use <a href="https://en.wikipedia.org/wiki/Camel_case" target="_blank">camelCase</a> formatting for variable names throughout the code.
15+
16+
5. Before committing, you can test your modifications by running the FEAScript library from a local server. To do this, use a <a href="https://docs.python.org/3/library/http.server.html" target="_blank">Python HTTP Server</a> by executing the following <a href="https://github.com/FEAScript/FEAScript-website/blob/main/corsHttpServer.py" target="_blank">script</a>. Start the Python server by running `python3 corsHttpServer.py` in your local repository folder. The server address will be http://127.0.0.1:8000/. For more details, see the instructions under the 'Import the FEAScript library from a local server' section in the <a href="https://github.com/FEAScript/FEAScript-website/blob/main/exampleHeatTrasnfer.html" target="_blank">2D heat transfer example</a>.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 FEAScript
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<img src="https://feascript.github.io/FEAScript-website/images/FEAScriptLogo.png" width="80" >
2+
3+
## Introduction
4+
5+
<a href="https://feascript.com/" target="_blank">FEAScript</a> is an open-source JavaScript library for solving differential equations using the finite element method. It allows you to create and run browser-based simulations of physics and engineering problems.
6+
<br>
7+
</br>
8+
FEAScript is in early-development and new features and improvements are constantly being added.
9+
10+
<!-- <img src="https://feascript.github.io/FEAScript-website/images/example1.png" width="400" > -->
11+
12+
## Contributing
13+
14+
We are actively seeking developers to help evolve FEAScript. Please refer to <a href="./CONTRIBUTING.md" target="_blank">CONTRIBUTING.md</a> for instructions on how to contribute.
15+
16+
## License
17+
18+
FEAScript is distributed under the terms of the <a href="./LICENSE" target="_blank">MIT license</a>. &#169; 2024 FEAScript.

src/FEAScript.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// ______ ______ _____ _ _ //
2+
// | ____| ____| /\ / ____| (_) | | //
3+
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
4+
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
5+
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
6+
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
7+
// | | | | //
8+
// |_| | |_ //
9+
// Website: https://feascript.com/ \__| //
10+
11+
import { assembleSolidHeatMatrix2D } from "./solvers/solidHeatScript.js";
12+
13+
/**
14+
* Differential equations solver using the finite element method
15+
* @param {string} solverScript - Parameter specifying the type of solver
16+
* @param {object} meshConfig - Object containing computational mesh details
17+
* @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis
18+
* @returns {object} An object containing the solution vector and additional mesh information
19+
*/
20+
export function FEAScript(solverScript, meshConfig, boundaryConditions) {
21+
let jacobianMatrix = []; // Jacobian matrix
22+
let residualVector = []; // Galerkin residuals
23+
let totalNodesX; // Total number of nodes along x-axis
24+
let totalNodesY; // Total number of nodes along y-axis
25+
let nodeXCoordinates = []; // Array to store x-coordinates of nodes (local numbering)
26+
let nodeYCoordinates = []; // Array to store y-coordinates of nodes (local numbering)
27+
let solutionVector = []; // Solution vector
28+
29+
// Assembly matrices
30+
console.time("assemblyMatrices");
31+
if (solverScript === "solidHeatScript") {
32+
console.log("solverScript:", solverScript);
33+
({
34+
jacobianMatrix,
35+
residualVector,
36+
totalNodesX,
37+
totalNodesY,
38+
nodeXCoordinates,
39+
nodeYCoordinates,
40+
} = assembleSolidHeatMatrix2D(meshConfig, boundaryConditions));
41+
}
42+
console.timeEnd("assemblyMatrices");
43+
let numNodesX = totalNodesX; // Assign the value of totalNodesX to numNodesX
44+
let numNodesY = totalNodesY; // Assign the value of totalNodesY to numNodesY
45+
46+
// System solving
47+
console.time("systemSolving");
48+
solutionVector = math.lusolve(jacobianMatrix, residualVector); // Solve the system of linear equations using LU decomposition
49+
console.timeEnd("systemSolving");
50+
51+
// Debugger;
52+
//console.log(x); // Log the solution to the console
53+
54+
// Return the solution matrix
55+
return {
56+
solutionVector,
57+
numNodesX,
58+
numNodesY,
59+
nodeXCoordinates,
60+
nodeYCoordinates,
61+
};
62+
}

src/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// ______ ______ _____ _ _ //
2+
// | ____| ____| /\ / ____| (_) | | //
3+
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
4+
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
5+
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
6+
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
7+
// | | | | //
8+
// |_| | |_ //
9+
// Website: https://feascript.com/ \__| //
10+
11+
export { FEAScript } from "./FEAScript.js";
12+
export { plotSolution2D } from "./visualization/plotSolutionScript.js";
13+
export { FEAScriptVersion } from "./utilities/helperFunctionsScript.js";

src/mesh/FEAMeshScript.js

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// ______ ______ _____ _ _ //
2+
// | ____| ____| /\ / ____| (_) | | //
3+
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
4+
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
5+
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
6+
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
7+
// | | | | //
8+
// |_| | |_ //
9+
// Website: https://feascript.com/ \__| //
10+
11+
export class FEAMesh {
12+
/**
13+
* Constructor to initialize the Mesh object
14+
* @param {object} config - Configuration object for the mesh
15+
* @param {number} config.numElementsX - Number of elements along the x-axis
16+
* @param {number} config.maxX - Maximum x-coordinate of the mesh
17+
* @param {number} [config.numElementsY=1] - Number of elements along the y-axis (default is 1 for 1D meshes)
18+
* @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (default is 0 for 1D meshes)
19+
* @param {string} [config.dimension='2D'] - The dimension of the mesh, either 1D or 2D (default is 2D)
20+
* @param {string} [config.meshFile=null] - Optional mesh file (JSON) for predefined meshes
21+
*/
22+
constructor({
23+
numElementsX,
24+
maxX,
25+
numElementsY = 1,
26+
maxY = 0,
27+
dimension = "2D",
28+
meshFile = null,
29+
}) {
30+
this.numElementsX = numElementsX;
31+
this.numElementsY = numElementsY;
32+
this.maxX = maxX;
33+
this.maxY = maxY;
34+
this.dimension = dimension;
35+
this.meshFile = meshFile;
36+
}
37+
38+
/**
39+
* Generate the mesh based on the dimension or custom mesh file
40+
* @returns {object} The generated mesh containing node coordinates and total nodes
41+
*/
42+
generateMesh() {
43+
if (this.meshFile) {
44+
// If a custom mesh file is provided, read and parse it
45+
const meshData = this.generateMeshFromCustomFile(this.meshFile);
46+
return meshData;
47+
} else {
48+
// Generate mesh based on dimension
49+
if (this.dimension === "1D") {
50+
return this.generateMesh1D();
51+
} else {
52+
return this.generateMesh2D();
53+
}
54+
}
55+
}
56+
57+
/**
58+
* Parse a custom mesh JSON file and generate the mesh
59+
* @param {string} meshFilePath - Path to the custom mesh file (JSON format)
60+
* @returns {object} Mesh data containing coordinates and connectivity
61+
*/
62+
generateMeshFromCustomFile(meshFilePath) {
63+
const response = fetch(meshFilePath);
64+
const meshData = response.json();
65+
66+
const nodeXCoordinates = [];
67+
const nodeYCoordinates = [];
68+
const { nodes, elements } = meshData;
69+
70+
// Parse the node coordinates
71+
nodes.forEach((node) => {
72+
nodeXCoordinates.push(node.x);
73+
nodeYCoordinates.push(node.y);
74+
});
75+
76+
return {
77+
nodeXCoordinates,
78+
nodeYCoordinates,
79+
totalNodesX: nodeXCoordinates.length,
80+
totalNodesY: nodeYCoordinates.length,
81+
elements,
82+
};
83+
}
84+
85+
/**
86+
* Generate a one-dimensional mesh along the x-axis
87+
* The method divides the x-axis into equal segments based on the number of elements
88+
* @returns {object} An object containing the x-coordinates of the nodes and the total number of nodes along the x-axis
89+
*/
90+
generateMesh1D() {
91+
let nodeXCoordinates = [];
92+
const xStart = 0;
93+
let totalNodesX = 2 * this.numElementsX + 1;
94+
const deltaX = (this.maxX - xStart) / this.numElementsX;
95+
96+
nodeXCoordinates[0] = xStart;
97+
for (let i = 1; i < totalNodesX; i++) {
98+
nodeXCoordinates[i] = nodeXCoordinates[i - 1] + deltaX;
99+
}
100+
101+
return { nodeXCoordinates, totalNodesX };
102+
}
103+
104+
/**
105+
* Generate a two-dimensional structured mesh.
106+
* The method creates a structured grid where nodes are placed at regular intervals along the x and y axes
107+
* @returns {object} An object containing the x and y coordinates and the total number of nodes
108+
*/
109+
generateMesh2D() {
110+
let nodeXCoordinates = [];
111+
let nodeYCoordinates = [];
112+
const xStart = 0;
113+
const yStart = 0;
114+
let totalNodesX = 2 * this.numElementsX + 1;
115+
let totalNodesY = 2 * this.numElementsY + 1;
116+
const deltaX = (this.maxX - xStart) / this.numElementsX;
117+
const deltaY = (this.maxY - yStart) / this.numElementsY;
118+
119+
nodeXCoordinates[0] = xStart;
120+
nodeYCoordinates[0] = yStart;
121+
for (let i = 1; i < totalNodesY; i++) {
122+
nodeXCoordinates[i] = nodeXCoordinates[0];
123+
nodeYCoordinates[i] = nodeYCoordinates[0] + (i * deltaY) / 2;
124+
}
125+
for (let i = 1; i < totalNodesX; i++) {
126+
const nnode = i * totalNodesY;
127+
nodeXCoordinates[nnode] = nodeXCoordinates[0] + (i * deltaX) / 2;
128+
nodeYCoordinates[nnode] = nodeYCoordinates[0];
129+
for (let j = 1; j < totalNodesY; j++) {
130+
nodeXCoordinates[nnode + j] = nodeXCoordinates[nnode];
131+
nodeYCoordinates[nnode + j] =
132+
nodeYCoordinates[nnode] + (j * deltaY) / 2;
133+
}
134+
}
135+
136+
// Generate nodal numbering (NOP) array
137+
const nodalNumbering = this.generateNodalNumbering(
138+
this.numElementsX,
139+
this.numElementsY,
140+
totalNodesX,
141+
totalNodesY
142+
);
143+
144+
// Return x and y coordinates of nodes, total nodes, and NOP array
145+
return {
146+
nodeXCoordinates,
147+
nodeYCoordinates,
148+
totalNodesX,
149+
totalNodesY,
150+
nodalNumbering,
151+
};
152+
}
153+
154+
/**
155+
* Generate the nodal numbering (NOP) array for a 2D structured mesh
156+
* This array represents the connectivity between elements and their corresponding nodes
157+
* @param {number} numElementsX - Number of elements along the x-axis
158+
* @param {number} numElementsY - Number of elements along the y-axis
159+
* @param {number} totalNodesX - Total number of nodes along the x-axis
160+
* @param {number} totalNodesY - Total number of nodes along the y-axis
161+
* @returns {array} NOP - A 2D array which represents the element-to-node connectivity for the entire mesh
162+
*/
163+
generateNodalNumbering(numElementsX, numElementsY, totalNodesX, totalNodesY) {
164+
let elementIndex = 0;
165+
let nop = [];
166+
167+
for (let i = 0; i < numElementsX * numElementsY; i++) {
168+
nop.push([]);
169+
for (let j = 0; j < 9; j++) {
170+
nop[i][j] = 0;
171+
}
172+
}
173+
174+
/*
175+
Representation of the nodes in the case of quadratic rectangular elements
176+
177+
2__5__8
178+
| |
179+
1 4 7
180+
|__ __|
181+
0 3 6
182+
183+
*/
184+
185+
for (let i = 1; i <= numElementsX; i++) {
186+
for (let j = 1; j <= numElementsY; j++) {
187+
for (let k = 1; k <= 3; k++) {
188+
let l = 3 * k - 2;
189+
nop[elementIndex][l - 1] = totalNodesY * (2 * i + k - 3) + 2 * j - 1;
190+
nop[elementIndex][l] = nop[elementIndex][l - 1] + 1;
191+
nop[elementIndex][l + 1] = nop[elementIndex][l - 1] + 2;
192+
}
193+
elementIndex = elementIndex + 1;
194+
}
195+
}
196+
197+
return nop;
198+
}
199+
}

0 commit comments

Comments
 (0)