-
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathlinearSystemSolver.js
More file actions
151 lines (129 loc) · 5.85 KB
/
Copy pathlinearSystemSolver.js
File metadata and controls
151 lines (129 loc) · 5.85 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
147
148
149
150
151
/**
* ════════════════════════════════════════════════════════════════
* FEAScript Core Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.3.0 (RC) | https://feascript.com
* MIT License © 2023–2026 FEAScript
* ════════════════════════════════════════════════════════════════
*/
// Internal imports
import { jacobiSolver, mathjsLUSolver } from "../base/solvers/index.js";
import { basicLog, debugLog, errorLog } from "../utilities/logging.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 luSolverResult = mathjsLUSolver(jacobianMatrix, residualVector, { matrixType: "sparse" });
solutionVector = luSolverResult.solutionVector;
} 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 wrapperUrl = new URL("../workers/webgpuWorker.js", import.meta.url).href;
const workerCode = `import "${wrapperUrl}";`;
const blob = new Blob([workerCode], { type: "application/javascript" });
const worker = new Worker(URL.createObjectURL(blob), {
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 systemMatrix = Array.isArray(jacobianMatrix)
? jacobianMatrix
: jacobianMatrix?.toArray?.() ?? jacobianMatrix;
const rightHandSideVector = 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 initialGuess = new Array(rightHandSideVector.length).fill(0);
let result;
result = await computeEngine.webgpuJacobiSolver(systemMatrix, rightHandSideVector, initialGuess, {
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 };
}