-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathgeneralFormPDEScript.js
More file actions
261 lines (227 loc) · 9.27 KB
/
generalFormPDEScript.js
File metadata and controls
261 lines (227 loc) · 9.27 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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/**
* ════════════════════════════════════════════════════════════════
* FEAScript Core Library
* Lightweight Finite Element Simulation in JavaScript
* Version: 0.3.0 (RC) | https://un5peqtmyvbr2nu3.julianrbryant.com
* MIT License © 2023–2026 FEAScript
* ════════════════════════════════════════════════════════════════
*/
// Internal imports
import { initializeFEA, performIsoparametricMapping1D } from "../mesh/meshUtilsScript.js";
import { GenericBoundaryConditions } from "./genericBoundaryConditionsScript.js";
import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js";
/**
* Function to assemble the Jacobian matrix and residuals vector for the general form PDE model
* @param {object} meshData - Object containing prepared mesh data
* @param {object} boundaryConditions - Object containing boundary conditions
* @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE
* @returns {object} An object containing:
* - jacobianMatrix: The assembled Jacobian matrix
* - residualVector: The assembled residual vector
*/
export function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {
basicLog("Starting general form PDE matrix assembly...");
// Extract mesh data
const {
nodesXCoordinates,
nodesYCoordinates,
nop,
boundaryElements,
totalElements,
meshDimension,
elementOrder,
} = meshData;
// Extract coefficient functions
const { A, B, C, D } = coefficientFunctions;
// Initialize FEA components
const FEAData = initializeFEA(meshData);
const {
residualVector,
jacobianMatrix,
localToGlobalMap,
basisFunctions,
gaussPoints,
gaussWeights,
nodesPerElement,
} = FEAData;
if (meshDimension === "1D") {
// 1D general form PDE
// Matrix assembly
for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {
// Map local element nodes to global mesh nodes
for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {
// Convert to 0-based indexing
localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;
}
// Loop over Gauss points
for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {
// Get basis functions for the current Gauss point
const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(
gaussPoints[gaussPointIndex],
);
// Perform isoparametric mapping
const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({
basisFunction,
basisFunctionDerivKsi,
nodesXCoordinates,
localToGlobalMap,
nodesPerElement,
});
// Calculate the physical coordinate for this Gauss point
let xCoord = 0;
for (let i = 0; i < nodesPerElement; i++) {
xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];
}
// Evaluate coefficient functions at this physical coordinate
const a = A(xCoord);
const b = B(xCoord);
const c = C(xCoord);
const d = D(xCoord);
// Computation of Galerkin's residuals and local Jacobian matrix
for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {
const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];
// Source term contribution to residual vector
residualVector[globalNodeIndex1] -=
gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];
for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) {
const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];
// Diffusion term
jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=
gaussWeights[gaussPointIndex] *
detJacobian *
a *
basisFunctionDerivX[localNodeIndex1] *
basisFunctionDerivX[localNodeIndex2];
// Advection term
jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=
gaussWeights[gaussPointIndex] *
detJacobian *
b *
basisFunctionDerivX[localNodeIndex2] *
basisFunction[localNodeIndex1];
// Reaction term
jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=
gaussWeights[gaussPointIndex] *
detJacobian *
c *
basisFunction[localNodeIndex1] *
basisFunction[localNodeIndex2];
}
}
}
}
} else if (meshDimension === "2D") {
errorLog("2D general form PDE is not yet supported in assembleGeneralFormPDEMat.");
// 2D general form PDE - empty for now
}
// Apply boundary conditions
const genericBoundaryConditions = new GenericBoundaryConditions(
boundaryConditions,
boundaryElements,
nop,
meshDimension,
elementOrder,
);
// Apply Dirichlet boundary conditions only
genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);
basicLog("General form PDE matrix assembly completed");
return {
jacobianMatrix,
residualVector,
};
}
/**
* Function to assemble the frontal solver matrix for the general form PDE model
* @param {object} data - Object containing element data for the frontal solver
* @returns {object} An object containing local Jacobian matrix and residual vector
*/
export function assembleGeneralFormPDEFront({
elementIndex,
nop,
meshData,
basisFunctions,
FEAData,
coefficientFunctions,
}) {
// Extract numerical integration parameters and mesh coordinates
const { gaussPoints, gaussWeights, nodesPerElement } = FEAData;
const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;
const { A, B, C, D } = coefficientFunctions;
// Initialize local Jacobian matrix and local residual vector
const localJacobianMatrix = Array(nodesPerElement)
.fill()
.map(() => Array(nodesPerElement).fill(0));
const localResidualVector = Array(nodesPerElement).fill(0);
// Build the mapping from local node indices to global node indices
const ngl = Array(nodesPerElement);
const localToGlobalMap = Array(nodesPerElement);
for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {
ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);
localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;
}
if (meshDimension === "1D") {
// 1D general form PDE
// Loop over Gauss points
for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {
// Get basis functions for the current Gauss point
const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(
gaussPoints[gaussPointIndex],
);
// Perform isoparametric mapping
const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({
basisFunction,
basisFunctionDerivKsi,
nodesXCoordinates,
localToGlobalMap,
nodesPerElement,
});
// Calculate the physical coordinate for this Gauss point
let xCoord = 0;
for (let i = 0; i < nodesPerElement; i++) {
xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];
}
// Evaluate coefficient functions at this physical coordinate
const a = A(xCoord);
const b = B(xCoord);
const c = C(xCoord);
const d = D(xCoord);
// Computation of local Jacobian matrix and residual vector
for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {
// Source term contribution to local residual vector
localResidualVector[localNodeIndex1] -=
gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];
for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) {
// Diffusion term
localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=
gaussWeights[gaussPointIndex] *
detJacobian *
a *
basisFunctionDerivX[localNodeIndex1] *
basisFunctionDerivX[localNodeIndex2];
// Advection term
localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=
gaussWeights[gaussPointIndex] *
detJacobian *
b *
basisFunctionDerivX[localNodeIndex2] *
basisFunction[localNodeIndex1];
// Reaction term
localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=
gaussWeights[gaussPointIndex] *
detJacobian *
c *
basisFunction[localNodeIndex1] *
basisFunction[localNodeIndex2];
}
}
}
} else if (meshDimension === "2D") {
errorLog("2D general form PDE is not yet supported in assembleGeneralFormPDEFront.");
// 2D general form PDE - empty for now
}
return {
localJacobianMatrix,
localResidualVector,
ngl,
};
}