Skip to content
Draft
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
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.

89 changes: 89 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"typescript": "^5.8.3"
},
"dependencies": {
"mathjs": "^14.6.0",
"taichi.js": "^0.0.36"
}
}
3 changes: 3 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ export default {
file: "dist/feascript.cjs.js",
format: "cjs",
sourcemap: true,
inlineDynamicImports: true,
},
{
file: "dist/feascript.esm.js",
format: "esm",
sourcemap: true,
inlineDynamicImports: true,
},
{
file: "dist/feascript.umd.js",
format: "umd",
name: "FEAScript",
sourcemap: true,
inlineDynamicImports: true,
},
],
plugins: [
Expand Down
27 changes: 12 additions & 15 deletions src/FEAScript.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// Website: https://feascript.com/ \__| //

// Internal imports
import { jacobiMethod } from "./methods/jacobiMethodScript.js";
import { solveLinearSystem } from "./methods/linearSystemSolverScript.js";
import { assembleSolidHeatTransferMat } from "./solvers/solidHeatTransferScript.js";
import { basicLog, debugLog, errorLog } from "./utilities/loggingScript.js";

Expand Down Expand Up @@ -79,23 +79,20 @@ export class FEAScriptModel {
// System solving
basicLog(`Solving system using ${this.solverMethod}...`);
console.time("systemSolving");
if (this.solverMethod === "lusolve") {
solutionVector = math.lusolve(jacobianMatrix, residualVector);
} else if (this.solverMethod === "jacobi") {
// Create initial guess of zeros
const initialGuess = new Array(residualVector.length).fill(0);
// Call Jacobi method with desired max iterations and tolerance
const jacobiResult = jacobiMethod(jacobianMatrix, residualVector, initialGuess, 1000, 1e-6);

// Log convergence information
if (jacobiResult.converged) {
debugLog(`Jacobi method converged in ${jacobiResult.iterations} iterations`);

// Use the centralized linear system solver
const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);
solutionVector = linearSystemResult.solutionVector;

// Log convergence information for iterative methods
if (linearSystemResult.iterations !== undefined) {
if (linearSystemResult.converged) {
debugLog(`${this.solverMethod} method converged in ${linearSystemResult.iterations} iterations`);
} else {
debugLog(`Jacobi method did not converge after ${jacobiResult.iterations} iterations`);
debugLog(`${this.solverMethod} method did not converge after ${linearSystemResult.iterations} iterations`);
}

solutionVector = jacobiResult.solution;
}

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

Expand Down
125 changes: 125 additions & 0 deletions src/methods/conjugateGradientSolverScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //

import { euclideanNorm } from "../utilities/helperFunctionsScript.js";

/**
* Function to solve a system of linear equations using the Conjugate Gradient iterative method
* This implementation uses Taichi.js for WebGPU acceleration with high precision (Float64)
* @param {array} A - The coefficient matrix (must be square and symmetric positive definite)
* @param {array} b - The right-hand side vector
* @param {array} x0 - Initial guess for solution vector
* @param {object} [options] - Options for the solver
* @param {number} [options.maxIterations=1000] - Maximum number of iterations
* @param {number} [options.tolerance=1e-6] - Convergence tolerance
* @returns {object} An object containing:
* - solutionVector: The solution vector
* - iterations: The number of iterations performed
* - converged: Boolean indicating whether the method converged
*/
export function conjugateGradientSolver(A, b, x0, options = {}) {
const { maxIterations = 1000, tolerance = 1e-6 } = options;

// For now, we'll use a basic JavaScript implementation with high precision
// This ensures synchronous operation while maintaining numerical precision

const n = A.length;
let x = [...x0]; // Current solution
let r = new Array(n); // Residual vector
let p = new Array(n); // Search direction
let Ap = new Array(n); // A*p

// Initialize residual r = b - A*x
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = 0; j < n; j++) {
sum += A[i][j] * x[j];
}
r[i] = b[i] - sum;
}

// Initialize search direction p = r
for (let i = 0; i < n; i++) {
p[i] = r[i];
}

let rsold = 0;
for (let i = 0; i < n; i++) {
rsold += r[i] * r[i];
}

let iterations = 0;
let converged = false;

for (let iteration = 0; iteration < maxIterations; iteration++) {
// Check convergence
const resNorm = Math.sqrt(rsold);
if (resNorm < tolerance) {
converged = true;
iterations = iteration;
break;
}

// Compute Ap = A*p
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = 0; j < n; j++) {
sum += A[i][j] * p[j];
}
Ap[i] = sum;
}

// Compute alpha = rsold / (p'*Ap)
let pAp = 0;
for (let i = 0; i < n; i++) {
pAp += p[i] * Ap[i];
}

if (Math.abs(pAp) < 1e-14) {
// Avoid division by zero
break;
}

const alpha = rsold / pAp;

// Update solution x = x + alpha*p
for (let i = 0; i < n; i++) {
x[i] += alpha * p[i];
}

// Update residual r = r - alpha*Ap
for (let i = 0; i < n; i++) {
r[i] -= alpha * Ap[i];
}

// Compute new rsold
let rsnew = 0;
for (let i = 0; i < n; i++) {
rsnew += r[i] * r[i];
}

// Compute beta = rsnew / rsold
const beta = rsnew / rsold;

// Update search direction p = r + beta*p
for (let i = 0; i < n; i++) {
p[i] = r[i] + beta * p[i];
}

rsold = rsnew;
iterations = iteration + 1;
}

return {
solutionVector: x,
iterations: iterations,
converged: converged,
};
}
Loading