-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathheatConductionScript.js
More file actions
273 lines (245 loc) · 11 KB
/
heatConductionScript.js
File metadata and controls
273 lines (245 loc) · 11 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
262
263
264
265
266
267
268
269
270
271
272
273
// ______ ______ _____ _ _ //
// | ____| ____| /\ / ____| (_) | | //
// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ //
// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| //
// | | | |____ / ____ \ ____) | (__| | | | |_) | | //
// |_| |______/_/ \_\_____/ \___|_| |_| __/| | //
// | | | | //
// |_| | |_ //
// Website: https://feascript.com/ \__| //
// Internal imports
import {
initializeFEA,
performIsoparametricMapping1D,
performIsoparametricMapping2D,
} from "../mesh/meshUtilsScript.js";
import { ThermalBoundaryConditions } from "./thermalBoundaryConditionsScript.js";
import { basicLog, debugLog } from "../utilities/loggingScript.js";
/**
* Function to assemble the Jacobian matrix and residuals vector for the solid heat transfer model
* @param {object} meshData - Object containing prepared mesh data
* @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis
* @returns {object} An object containing:
* - jacobianMatrix: The assembled Jacobian matrix
* - residualVector: The assembled residual vector
*
* For consistency across both linear and nonlinear formulations,
* this project always refers to the assembled right-hand side vector
* as `residualVector` and the assembled system matrix as `jacobianMatrix`.
*
* In linear problems `jacobianMatrix` is equivalent to the
* classic stiffness/conductivity matrix and `residualVector`
* corresponds to the traditional load (RHS) vector.
*/
export function assembleHeatConductionMat(meshData, boundaryConditions) {
basicLog("Starting solid heat transfer matrix assembly...");
// Extract mesh data
const {
nodesXCoordinates,
nodesYCoordinates,
nop,
boundaryElements,
totalElements,
meshDimension,
elementOrder,
} = meshData;
// Initialize FEA components
const FEAData = initializeFEA(meshData);
const {
residualVector,
jacobianMatrix,
localToGlobalMap,
basisFunctions,
gaussPoints,
gaussWeights,
numNodes,
} = FEAData;
// Matrix assembly
for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {
// Map local element nodes to global mesh nodes
for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {
// Subtract 1 from nop in order to start numbering from 0
localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;
}
// Loop over Gauss points
for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {
// 1D solid heat transfer
if (meshDimension === "1D") {
// Get basis functions for the current Gauss point
const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);
// Perform isoparametric mapping
const mappingResult = performIsoparametricMapping1D({
basisFunction: basisFunctionsAndDerivatives.basisFunction,
basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,
nodesXCoordinates,
localToGlobalMap,
numNodes,
});
// Extract mapping results
const { detJacobian, basisFunctionDerivX } = mappingResult;
// Computation of Galerkin's residuals and Jacobian matrix
for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {
let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];
// residualVector is zero for this case
for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {
let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];
jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=
-gaussWeights[gaussPointIndex1] *
detJacobian *
(basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);
}
}
}
// 2D solid heat transfer
else if (meshDimension === "2D") {
for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {
// Get basis functions for the current Gauss point
const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(
gaussPoints[gaussPointIndex1],
gaussPoints[gaussPointIndex2]
);
// Perform isoparametric mapping
const mappingResult = performIsoparametricMapping2D({
basisFunction: basisFunctionsAndDerivatives.basisFunction,
basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,
basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,
nodesXCoordinates,
nodesYCoordinates,
localToGlobalMap,
numNodes,
});
// Extract mapping results
const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;
// Computation of Galerkin's residuals and Jacobian matrix
for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {
let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];
// residualVector is zero for this case
for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {
let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];
jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=
-gaussWeights[gaussPointIndex1] *
gaussWeights[gaussPointIndex2] *
detJacobian *
(basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +
basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);
}
}
}
}
}
}
// Apply boundary conditions
const thermalBoundaryConditions = new ThermalBoundaryConditions(
boundaryConditions,
boundaryElements,
nop,
meshDimension,
elementOrder
);
// Impose Convection boundary conditions
thermalBoundaryConditions.imposeConvectionBoundaryConditions(
residualVector,
jacobianMatrix,
gaussPoints,
gaussWeights,
nodesXCoordinates,
nodesYCoordinates,
basisFunctions
);
// Impose ConstantTemp boundary conditions
thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);
basicLog("Solid heat transfer matrix assembly completed");
return {
jacobianMatrix,
residualVector,
};
}
/**
* Function to assemble the local Jacobian matrix and residual vector for the solid heat transfer model when using the frontal system solver
* @param {number} elementIndex - Index of the element being processed
* @param {array} nop - Nodal connectivity array (element-to-node mapping)
* @param {object} meshData - Object containing prepared mesh data
* @param {object} basisFunctions - Object containing basis functions and their derivatives
* @param {object} FEAData - Object containing FEA-related data
* @returns {object} An object containing:
* - localJacobianMatrix: Local Jacobian matrix
* - localResidualVector: Residual vector contributions
* - ngl: Array mapping local node indices to global node indices
*/
export function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {
// Extract numerical integration parameters and mesh coordinates
const { gaussPoints, gaussWeights, numNodes } = FEAData;
const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;
// Initialize local Jacobian matrix and local residual vector
const localJacobianMatrix = Array(numNodes)
.fill()
.map(() => Array(numNodes).fill(0));
const localResidualVector = Array(numNodes).fill(0);
// Build the mapping from local node indices to global node indices
const ngl = Array(numNodes);
const localToGlobalMap = Array(numNodes);
for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {
ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);
localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;
}
// Loop over Gauss points
if (meshDimension === "1D") {
// 1D solid heat transfer
for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {
// Get basis functions for the current Gauss point
const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(
gaussPoints[gaussPointIndex1]
);
// Perform isoparametric mapping
const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({
basisFunction,
basisFunctionDerivKsi,
nodesXCoordinates,
localToGlobalMap,
numNodes,
});
// Computation of Galerkin's residuals and local Jacobian matrix
for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {
for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {
localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=
gaussWeights[gaussPointIndex1] *
detJacobian *
(basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);
}
}
}
} else if (meshDimension === "2D") {
// 2D solid heat transfer
for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {
for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {
// Get basis functions for the current Gauss point
const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =
basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);
// Create mapping from local element space to global mesh (convert to 0-based indexing)
const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);
// Perform isoparametric mapping
const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({
basisFunction,
basisFunctionDerivKsi,
basisFunctionDerivEta,
nodesXCoordinates,
nodesYCoordinates,
localToGlobalMap,
numNodes,
});
// Computation of Galerkin's residuals and local Jacobian matrix
for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {
for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {
localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=
gaussWeights[gaussPointIndex1] *
gaussWeights[gaussPointIndex2] *
detJacobian *
(basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +
basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);
}
}
}
}
}
return { localJacobianMatrix, localResidualVector, ngl };
}