@@ -46,10 +46,17 @@ export class FEAScriptModel {
4646 this . solverConfig = solverConfig ;
4747
4848 // Store coefficient functions if provided
49- if ( options && options . coefficientFunctions ) {
49+ if ( options ? .coefficientFunctions ) {
5050 this . coefficientFunctions = options . coefficientFunctions ;
5151 debugLog ( "Coefficient functions set" ) ;
5252 }
53+ // Only update if a value is provided, otherwise keep the default
54+ if ( options ?. maxIterations !== undefined ) {
55+ this . maxIterations = options . maxIterations ;
56+ }
57+ if ( options ?. tolerance !== undefined ) {
58+ this . tolerance = options . tolerance ;
59+ }
5360
5461 debugLog ( `Solver config set to: ${ solverConfig } ` ) ;
5562 }
@@ -69,67 +76,15 @@ export class FEAScriptModel {
6976 debugLog ( `Solver method set to: ${ solverMethod } ` ) ;
7077 }
7178
72- async solveWithWebgpu ( computeEngine ) {
73- if ( ! this . solverConfig || ! this . meshConfig || ! this . boundaryConditions ) {
74- errorLog ( "Solver config, mesh config, and boundary conditions must be set before solving." ) ;
75- }
76-
77- let jacobianMatrix = [ ] ;
78- let residualVector = [ ] ;
79- let solutionVector = [ ] ;
80- let nodesCoordinates = { } ;
81-
82- // Prepare the mesh
83- basicLog ( "Preparing mesh..." ) ;
84- const meshData = prepareMesh ( this . meshConfig ) ;
85- basicLog ( "Mesh preparation completed" ) ;
86-
87- // Extract node coordinates from meshData
88- nodesCoordinates = {
89- nodesXCoordinates : meshData . nodesXCoordinates ,
90- nodesYCoordinates : meshData . nodesYCoordinates ,
91- } ;
92-
93- // Assembly matrices
94- basicLog ( "Beginning matrix assembly..." ) ;
95- console . time ( "assemblyMatrices" ) ;
96- basicLog ( `Using solver: ${ this . solverConfig } ` ) ;
97- if ( this . solverConfig === "solidHeatTransferScript" ) {
98- ( { jacobianMatrix, residualVector } = assembleHeatConductionMat (
99- meshData ,
100- this . boundaryConditions
101- ) ) ;
102- }
103- console . timeEnd ( "assemblyMatrices" ) ;
104- basicLog ( "Matrix assembly completed" ) ;
105-
106- // System solving with WebGPU Jacobi
107- basicLog ( "Solving system using WebGPU Jacobi..." ) ;
108- console . time ( "systemSolving" ) ;
109-
110- // Convert matrices to arrays for WebGPU
111- const A = Array . isArray ( jacobianMatrix ) ? jacobianMatrix : jacobianMatrix . toArray ( ) ;
112- const b = Array . isArray ( residualVector ) ? residualVector : residualVector . toArray ( ) ;
113-
114- // For heat conduction FEM, the matrix might be negative definite
115- console . log ( "Matrix diagonal sample:" , A . slice ( 0 , 5 ) . map ( ( row , i ) => row [ i ] ) ) ;
116- console . log ( "RHS sample:" , b . slice ( 0 , 5 ) ) ;
117-
118- // Use WebGPU Jacobi method
119- const initialGuess = new Array ( b . length ) . fill ( 0 ) ;
120- solutionVector = await computeEngine . webgpuJacobiSolver ( A , b , initialGuess , 10000 , 1e-3 ) ;
121-
122- console . timeEnd ( "systemSolving" ) ;
123- basicLog ( "System solved successfully with WebGPU Jacobi" ) ;
124-
125- return { solutionVector, nodesCoordinates } ;
126- }
127-
128- solve ( ) {
79+ /**
80+ * Function to solve the finite element problem synchronously
81+ * @param {object } [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`
82+ * @returns {object } An object containing the solution vector and the coordinates of the mesh nodes
83+ */
84+ solve ( options = { } ) {
12985 if ( ! this . solverConfig || ! this . meshConfig || ! this . boundaryConditions ) {
13086 errorLog ( "Solver config, mesh config, and boundary conditions must be set before solving." ) ;
13187 }
132-
13388 /**
13489 * For consistency across both linear and nonlinear formulations,
13590 * this project always refers to the assembled right-hand side vector
@@ -172,7 +127,10 @@ export class FEAScriptModel {
172127 } else {
173128 // Use regular linear solver methods
174129 ( { jacobianMatrix, residualVector } = assembleHeatConductionMat ( meshData , this . boundaryConditions ) ) ;
175- const linearSystemResult = solveLinearSystem ( this . solverMethod , jacobianMatrix , residualVector ) ;
130+ const linearSystemResult = solveLinearSystem ( this . solverMethod , jacobianMatrix , residualVector , {
131+ maxIterations : options . maxIterations ?? this . maxIterations ,
132+ tolerance : options . tolerance ?? this . tolerance ,
133+ } ) ;
176134 solutionVector = linearSystemResult . solutionVector ;
177135 }
178136 } else if ( this . solverConfig === "frontPropagationScript" ) {
@@ -187,6 +145,9 @@ export class FEAScriptModel {
187145 eikonalActivationFlag : eikonalActivationFlag ,
188146 solverMethod : this . solverMethod ,
189147 initialSolution,
148+ // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver
149+ maxIterations : options . maxIterations ?? this . maxIterations ,
150+ tolerance : options . tolerance ?? this . tolerance ,
190151 } ;
191152
192153 while ( eikonalActivationFlag <= 1 ) {
@@ -199,7 +160,7 @@ export class FEAScriptModel {
199160 }
200161
201162 // Solve the assembled non-linear system
202- const newtonRaphsonResult = newtonRaphson ( assembleFrontPropagationMat , context , 100 , 1e-4 ) ;
163+ const newtonRaphsonResult = newtonRaphson ( assembleFrontPropagationMat , context ) ;
203164
204165 // Extract results
205166 jacobianMatrix = newtonRaphsonResult . jacobianMatrix ;
@@ -223,7 +184,10 @@ export class FEAScriptModel {
223184 this . coefficientFunctions
224185 ) ) ;
225186
226- const linearSystemResult = solveLinearSystem ( this . solverMethod , jacobianMatrix , residualVector ) ;
187+ const linearSystemResult = solveLinearSystem ( this . solverMethod , jacobianMatrix , residualVector , {
188+ maxIterations : options . maxIterations ?? this . maxIterations ,
189+ tolerance : options . tolerance ?? this . tolerance ,
190+ } ) ;
227191 solutionVector = linearSystemResult . solutionVector ;
228192 }
229193 }
@@ -233,6 +197,12 @@ export class FEAScriptModel {
233197 return { solutionVector, nodesCoordinates } ;
234198 }
235199
200+ /**
201+ * Function to solve the finite element problem asynchronously
202+ * @param {object } computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)
203+ * @param {object } [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`
204+ * @returns {Promise<object> } A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes
205+ */
236206 async solveAsync ( computeEngine , options = { } ) {
237207 if ( ! this . solverConfig || ! this . meshConfig || ! this . boundaryConditions ) {
238208 errorLog ( "Solver config, mesh config, and boundary conditions must be set before solving." ) ;
@@ -260,18 +230,18 @@ export class FEAScriptModel {
260230 if ( this . solverMethod === "jacobi-gpu" ) {
261231 const { solutionVector : x } = await solveLinearSystemAsync ( "jacobi-gpu" , jacobianMatrix , residualVector , {
262232 computeEngine,
263- maxIterations : options . maxIterations ,
264- tolerance : options . tolerance ,
233+ maxIterations : options . maxIterations ?? this . maxIterations ,
234+ tolerance : options . tolerance ?? this . tolerance ,
265235 } ) ;
266236 solutionVector = x ;
267237 } else {
268- const { solutionVector : x } = solveLinearSystem ( this . solverMethod , jacobianMatrix , residualVector ) ;
269- solutionVector = x ;
238+ // Other async solver
270239 }
271240 }
272241 console . timeEnd ( "totalSolvingTime" ) ;
273242 basicLog ( "Solving process completed" ) ;
274243
275244 return { solutionVector, nodesCoordinates } ;
276245 }
246+
277247}
0 commit comments