-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathnewtonRaphson.js
More file actions
105 lines (90 loc) · 3.75 KB
/
newtonRaphson.js
File metadata and controls
105 lines (90 loc) · 3.75 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
/**
* ════════════════════════════════════════════════════════════════
* 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 { euclideanNorm } from "../methods/euclideanNorm.js";
import { solveLinearSystem } from "./linearSystemSolver.js";
import { basicLog, debugLog, errorLog } from "../utilities/logging.js";
import { runFrontalSolver } from "./frontalSolver.js";
import { assembleFrontPropagationFront } from "../models/frontPropagation.js";
/**
* Function to solve a system of non-linear equations using the Newton-Raphson method
* @param {function} assembleMat - Matrix assembler based on the physical model
* @param {object} context - Context object containing simulation data and options
* @returns {object} An object containing:
* - solutionVector: The solution vector
* - iterations: The number of iterations performed
* - converged: Boolean indicating whether the method converged
*/
export function newtonRaphson(assembleMat, context = {}) {
let errorNorm = 0;
let converged = false;
let iterations = 0;
let deltaX = [];
let solutionVector = [];
let jacobianMatrix = [];
let residualVector = [];
// Extract context
const { maxIterations = 100, tolerance = 1e-4 } = context;
// Calculate system size
let totalNodes = context.meshData.nodesXCoordinates.length;
// Initialize arrays with proper size
for (let i = 0; i < totalNodes; i++) {
deltaX[i] = 0;
solutionVector[i] = 0;
}
// Initialize solution from context if available
if (context.initialSolution && context.initialSolution.length === totalNodes) {
solutionVector = [...context.initialSolution];
}
while (iterations < maxIterations && !converged) {
// Update solution
for (let i = 0; i < solutionVector.length; i++) {
solutionVector[i] = solutionVector[i] + deltaX[i];
}
// Check if using frontal solver
if (context.solverMethod === "frontal") {
const frontalResult = runFrontalSolver(
assembleFrontPropagationFront,
context.meshData,
context.boundaryConditions,
{ solutionVector, eikonalActivationFlag: context.eikonalActivationFlag },
);
deltaX = frontalResult.solutionVector;
} else {
// Compute Jacobian and residual matrices
({ jacobianMatrix, residualVector } = assembleMat(
context.meshData,
context.boundaryConditions,
solutionVector, // The solution vector is required in the case of a non-linear equation
context.eikonalActivationFlag, // Currently used only in the front propagation solver (TODO refactor in case of a solver not needing it)
));
// Solve the linear system based on the specified solver method
const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);
deltaX = linearSystemResult.solutionVector;
}
// Check convergence
errorNorm = euclideanNorm(deltaX);
// Norm for each iteration
basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);
if (errorNorm <= tolerance) {
converged = true;
} else if (errorNorm > 1e2) {
errorLog(`Solution not converged. Error norm: ${errorNorm}`);
break;
}
iterations++;
}
return {
solutionVector,
converged,
iterations,
jacobianMatrix,
residualVector,
};
}