-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathlinearSystemSolverScript.js
More file actions
146 lines (122 loc) · 5.78 KB
/
linearSystemSolverScript.js
File metadata and controls
146 lines (122 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* ════════════════════════════════════════════════════════════════
* FEAScript Core Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.2.0 | https://feascript.com
* MIT License © 2023–2026 FEAScript
* ════════════════════════════════════════════════════════════════
*/
// Internal imports
import { jacobiSolver } from "./jacobiSolverScript.js";
import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js";
import * as Comlink from "../vendor/comlink.mjs";
/**
* Function to solve a system of linear equations using different solver methods
* @param {string} solverMethod - The solver method to use ("lusolve" or "jacobi")
* @param {Array} jacobianMatrix - The coefficient matrix
* @param {Array} residualVector - The right-hand side vector
* @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`
* @returns {object} An object containing:
* - solutionVector: The solution vector
* - converged: Boolean indicating whether the method converged (for iterative methods)
* - iterations: Number of iterations performed (for iterative methods)
*/
export function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {
// Extract options
const { maxIterations = 10000, tolerance = 1e-4 } = options;
let solutionVector = [];
let converged = true;
let iterations = 0;
// Solve the linear system based on the specified solver method
basicLog(`Solving system using ${solverMethod}...`);
console.time("systemSolving");
if (solverMethod === "lusolve") {
// Use LU decomposition method
const jacobianMatrixSparse = math.sparse(jacobianMatrix);
const luFactorization = math.slu(jacobianMatrixSparse, 1, 1); // order=1, threshold=1 for pivoting
let solutionMatrix = math.lusolve(luFactorization, residualVector);
solutionVector = math.squeeze(solutionMatrix).valueOf();
//solutionVector = math.lusolve(jacobianMatrix, residualVector); // In the case of a dense matrix
} else if (solverMethod === "jacobi") {
// Use Jacobi method
const initialGuess = new Array(residualVector.length).fill(0);
const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {
maxIterations,
tolerance,
});
// Log convergence information
if (jacobiSolverResult.converged) {
debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);
} else {
errorLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);
}
solutionVector = jacobiSolverResult.solutionVector;
converged = jacobiSolverResult.converged;
iterations = jacobiSolverResult.iterations;
} else {
errorLog(`Unknown solver method: ${solverMethod}`);
}
console.timeEnd("systemSolving");
basicLog("System solved successfully");
return { solutionVector, converged, iterations };
}
// Helper to lazily create a default WebGPU compute engine (Comlink + worker)
async function createDefaultComputeEngine() {
const worker = new Worker(new URL("../workers/webgpuWorkerScript.js", import.meta.url), {
type: "module",
});
const computeEngine = Comlink.wrap(worker);
await computeEngine.initialize();
return { computeEngine, worker };
}
/**
* Function to solve asynchronously a system of linear equations using different solver methods
* @param {string} solverMethod - The solver method to use (e.g., "jacobi-gpu")
* @param {array} jacobianMatrix - The coefficient matrix
* @param {array} residualVector - The right-hand side vector
* @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`
* @returns {Promise<object>} A promise that resolves to an object containing:
* - solutionVector: The solution vector
* - converged: Boolean indicating whether the method converged (for iterative methods)
* - iterations: Number of iterations performed (for iterative methods)
*/
export async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {
// Extract options
const { maxIterations = 10000, tolerance = 1e-4 } = options;
basicLog(`Solving system using ${solverMethod}...`);
console.time("systemSolving");
// Normalize inputs
const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;
const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;
let created = null;
let computeEngine = null;
let solutionVector = [];
let converged = true;
let iterations;
if (solverMethod === "jacobi-gpu") {
// Spin up a worker-backed compute engine
created = await createDefaultComputeEngine();
computeEngine = created.computeEngine;
const x0 = new Array(b.length).fill(0);
let result;
result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });
solutionVector = result.solutionVector;
converged = result.converged;
iterations = result.iterations;
// Log convergence information
if (converged) {
debugLog(`Jacobi method converged in ${iterations} iterations`);
} else {
errorLog(`Jacobi method did not converge after ${iterations} iterations`);
}
} else {
errorLog(`Unknown solver method: ${solverMethod}`);
}
console.timeEnd("systemSolving");
basicLog(`System solved successfully (${solverMethod})`);
if (created) {
await computeEngine?.destroy?.().catch(() => { });
created.worker.terminate();
}
return { solutionVector, converged, iterations };
}