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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Thank you for your interest in contributing! FEAScript is in early development,

All files in the FEAScript-core codebase should follow this structure:

1. Banner: All files start with the FEAScript ASCII art banner
1. Banner: All files start with the FEAScript banner
2. Imports:
- External imports first, alphabetically ordered
- Internal imports next, grouped by module/folder
Expand All @@ -41,15 +41,13 @@ All files in the FEAScript-core codebase should follow this structure:
Example:

```javascript
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: {VERSION} | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// External imports
import { mathLibrary } from "math-package";
Expand Down
4 changes: 2 additions & 2 deletions dist/feascript.cjs.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/feascript.cjs.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/feascript.esm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/feascript.esm.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/feascript.umd.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/feascript.umd.js.map

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Import Math.js
import * as math from "mathjs";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Import Math.js
import * as math from "mathjs";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Import Math.js
import * as math from "mathjs";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Import Math.js
import * as math from "mathjs";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Import required Node.js modules
import fs from "fs";
Expand Down
126 changes: 45 additions & 81 deletions src/FEAScript.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Internal imports
import { newtonRaphson } from "./methods/newtonRaphsonScript.js";
Expand Down Expand Up @@ -48,10 +46,17 @@ export class FEAScriptModel {
this.solverConfig = solverConfig;

// Store coefficient functions if provided
if (options && options.coefficientFunctions) {
if (options?.coefficientFunctions) {
this.coefficientFunctions = options.coefficientFunctions;
debugLog("Coefficient functions set");
}
// Only update if a value is provided, otherwise keep the default
if (options?.maxIterations !== undefined) {
this.maxIterations = options.maxIterations;
}
if (options?.tolerance !== undefined) {
this.tolerance = options.tolerance;
}

debugLog(`Solver config set to: ${solverConfig}`);
}
Expand All @@ -71,67 +76,15 @@ export class FEAScriptModel {
debugLog(`Solver method set to: ${solverMethod}`);
}

async solveWithWebgpu(computeEngine) {
if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {
errorLog("Solver config, mesh config, and boundary conditions must be set before solving.");
}

let jacobianMatrix = [];
let residualVector = [];
let solutionVector = [];
let nodesCoordinates = {};

// Prepare the mesh
basicLog("Preparing mesh...");
const meshData = prepareMesh(this.meshConfig);
basicLog("Mesh preparation completed");

// Extract node coordinates from meshData
nodesCoordinates = {
nodesXCoordinates: meshData.nodesXCoordinates,
nodesYCoordinates: meshData.nodesYCoordinates,
};

// Assembly matrices
basicLog("Beginning matrix assembly...");
console.time("assemblyMatrices");
if (this.solverConfig === "solidHeatTransferScript") {
basicLog(`Using solver: ${this.solverConfig}`);
({ jacobianMatrix, residualVector } = assembleHeatConductionMat(
meshData,
this.boundaryConditions
));
}
console.timeEnd("assemblyMatrices");
basicLog("Matrix assembly completed");

// System solving with WebGPU Jacobi
basicLog("Solving system using WebGPU Jacobi...");
console.time("systemSolving");

// Convert matrices to arrays for WebGPU
const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix.toArray();
const b = Array.isArray(residualVector) ? residualVector : residualVector.toArray();

// For heat conduction FEM, the matrix might be negative definite
console.log("Matrix diagonal sample:", A.slice(0, 5).map((row, i) => row[i]));
console.log("RHS sample:", b.slice(0, 5));

// Use WebGPU Jacobi method
const initialGuess = new Array(b.length).fill(0);
solutionVector = await computeEngine.webgpuJacobiSolver(A, b, initialGuess, 10000, 1e-3);

console.timeEnd("systemSolving");
basicLog("System solved successfully with WebGPU Jacobi");

return { solutionVector, nodesCoordinates };
}

solve() {
/**
* Function to solve the finite element problem synchronously
* @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`
* @returns {object} An object containing the solution vector and the coordinates of the mesh nodes
*/
solve(options = {}) {
if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {
errorLog("Solver config, mesh config, and boundary conditions must be set before solving.");
}

/**
* For consistency across both linear and nonlinear formulations,
* this project always refers to the assembled right-hand side vector
Expand Down Expand Up @@ -161,9 +114,8 @@ export class FEAScriptModel {
// Select and execute the appropriate solver based on solverConfig
basicLog("Beginning solving process...");
console.time("totalSolvingTime");
basicLog(`Using solver: ${this.solverConfig}`);
if (this.solverConfig === "heatConductionScript") {
basicLog(`Using solver: ${this.solverConfig}`);

// Check if using frontal solver
if (this.solverMethod === "frontal") {
const frontalResult = runFrontalSolver(
Expand All @@ -175,12 +127,13 @@ export class FEAScriptModel {
} else {
// Use regular linear solver methods
({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));
const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);
const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector, {
maxIterations: options.maxIterations ?? this.maxIterations,
tolerance: options.tolerance ?? this.tolerance,
});
solutionVector = linearSystemResult.solutionVector;
}
} else if (this.solverConfig === "frontPropagationScript") {
basicLog(`Using solver: ${this.solverConfig}`);

// Initialize eikonalActivationFlag
let eikonalActivationFlag = 0;
const eikonalExteralIterations = 5; // Number of incremental steps for the eikonal equation
Expand All @@ -192,6 +145,9 @@ export class FEAScriptModel {
eikonalActivationFlag: eikonalActivationFlag,
solverMethod: this.solverMethod,
initialSolution,
// TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver
maxIterations: options.maxIterations ?? this.maxIterations,
tolerance: options.tolerance ?? this.tolerance,
};

while (eikonalActivationFlag <= 1) {
Expand All @@ -204,7 +160,7 @@ export class FEAScriptModel {
}

// Solve the assembled non-linear system
const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);
const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context);

// Extract results
jacobianMatrix = newtonRaphsonResult.jacobianMatrix;
Expand All @@ -215,7 +171,6 @@ export class FEAScriptModel {
eikonalActivationFlag += 1 / eikonalExteralIterations;
}
} else if (this.solverConfig === "generalFormPDEScript") {
basicLog(`Using solver: ${this.solverConfig}`);
// Check if using frontal solver
if (this.solverMethod === "frontal") {
errorLog(
Expand All @@ -229,7 +184,10 @@ export class FEAScriptModel {
this.coefficientFunctions
));

const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);
const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector, {
maxIterations: options.maxIterations ?? this.maxIterations,
tolerance: options.tolerance ?? this.tolerance,
});
solutionVector = linearSystemResult.solutionVector;
}
}
Expand All @@ -239,6 +197,12 @@ export class FEAScriptModel {
return { solutionVector, nodesCoordinates };
}

/**
* Function to solve the finite element problem asynchronously
* @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)
* @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`
* @returns {Promise<object>} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes
*/
async solveAsync(computeEngine, options = {}) {
if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {
errorLog("Solver config, mesh config, and boundary conditions must be set before solving.");
Expand All @@ -259,25 +223,25 @@ export class FEAScriptModel {
basicLog("Beginning solving process...");
console.time("totalSolvingTime");

basicLog(`Using solver: ${this.solverConfig}`);
if (this.solverConfig === "heatConductionScript") {

({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));

if (this.solverMethod === "jacobi-gpu") {
const { solutionVector: x } = await solveLinearSystemAsync("jacobi-gpu", jacobianMatrix, residualVector, {
computeEngine,
maxIterations: options.maxIterations,
tolerance: options.tolerance,
maxIterations: options.maxIterations ?? this.maxIterations,
tolerance: options.tolerance ?? this.tolerance,
});
solutionVector = x;
} else {
const { solutionVector: x } = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);
solutionVector = x;
// Other async solver
}
}
console.timeEnd("totalSolvingTime");
basicLog("Solving process completed");

return { solutionVector, nodesCoordinates };
}

}
16 changes: 7 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

export { FEAScriptModel } from "./FEAScript.js";
export { importGmshQuadTri } from "./readers/gmshReaderScript.js";
Expand Down
16 changes: 7 additions & 9 deletions src/mesh/basisFunctionsScript.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
/**
* ════════════════════════════════════════════════════════════
* FEAScript Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.1.4 | https://feascript.com
* ════════════════════════════════════════════════════════════
*/

// Internal imports
import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js";
Expand Down
Loading