Skip to content

Commit fdb3e1d

Browse files
committedMay 7, 2025·
Initialize boundary elements as arrays and update plotSolution to support mesh type parameter for better visualization
1 parent d52ee93 commit fdb3e1d

File tree

2 files changed

+109
-87
lines changed

2 files changed

+109
-87
lines changed
 

‎src/readers/gmshReaderScript.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const importGmshQuadTri = async (file) => {
2121
quadElements: [],
2222
triangleElements: [],
2323
},
24-
boundaryElements: [],
24+
boundaryElements: [], // Will be initialized as array of arrays below
2525
boundaryConditions: [],
2626
gmshV: 0,
2727
ascii: false,
@@ -32,6 +32,11 @@ const importGmshQuadTri = async (file) => {
3232
elementTypes: {},
3333
};
3434

35+
// Initialize boundaryElements as an array of 4 empty arrays (one for each side)
36+
for (let i = 0; i < 4; i++) {
37+
result.boundaryElements[i] = [];
38+
}
39+
3540
let content = await file.text();
3641
let lines = content
3742
.split("\n")
@@ -273,6 +278,7 @@ const importGmshQuadTri = async (file) => {
273278
function processBoundaryElements(elements, boundaryElements, numNodes, elementType) {
274279
const edgeCount = {};
275280

281+
// Count occurrences of each edge
276282
for (let i = 0; i < elements.length; i++) {
277283
const element = elements[i];
278284

@@ -286,6 +292,7 @@ function processBoundaryElements(elements, boundaryElements, numNodes, elementTy
286292
}
287293
}
288294

295+
// Process boundary edges
289296
for (let i = 0; i < elements.length; i++) {
290297
const element = elements[i];
291298

@@ -295,12 +302,21 @@ function processBoundaryElements(elements, boundaryElements, numNodes, elementTy
295302

296303
const edgeKey = node1 < node2 ? `${node1}-${node2}` : `${node2}-${node1}`;
297304

298-
if (edgeCount[edgeKey] === 1) {
299-
boundaryElements.push({
300-
elementIndex: i,
301-
localEdgeIndex: j,
302-
elementType: elementType,
303-
});
305+
if (edgeCount[edgeKey] === 1) { // Boundary edge
306+
// Map local edge index to side index (0: bottom, 1: left, 2: top, 3: right)
307+
let sideIndex;
308+
309+
if (elementType === "quad") {
310+
// For quadrilateral elements
311+
// Gmsh format: 0 → bottom, 1 → right, 2 → top, 3 → left
312+
// Adjusted to match the FEAScript format: 0 → bottom, 1 → left, 2 → top, 3 → right
313+
const sideMap = [0, 3, 2, 1];
314+
sideIndex = sideMap[j];
315+
} else if (elementType === "triangle") {
316+
// For triangular elements
317+
}
318+
319+
boundaryElements[sideIndex].push([i, j]);
304320
}
305321
}
306322
}

‎src/visualization/plotSolutionScript.js

Lines changed: 86 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* @param {string} meshDimension - The dimension of the solution
1717
* @param {string} plotType - The type of plot
1818
* @param {string} plotDivId - The id of the div where the plot will be rendered
19-
* @param {boolean} showMesh - Flag to indicate if the mesh would be rendered
19+
* @param {string} [meshType="structured"] - Type of mesh: "structured" or "unstructured"
2020
*/
2121
export function plotSolution(
2222
solutionVector,
@@ -25,7 +25,7 @@ export function plotSolution(
2525
meshDimension,
2626
plotType,
2727
plotDivId,
28-
showMesh = false // Only applicable for rectangular domains when using generateMeshFromGeometry
28+
meshType = "structured"
2929
) {
3030
const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;
3131

@@ -65,92 +65,98 @@ export function plotSolution(
6565

6666
Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });
6767
} else if (meshDimension === "2D" && plotType === "contour") {
68-
// Calculate the number of nodes along the x-axis and y-axis
69-
const numNodesX = new Set(nodesXCoordinates).size;
70-
const numNodesY = new Set(nodesYCoordinates).size;
71-
72-
// Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions
73-
let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);
74-
let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);
75-
76-
// Reshape the solution array to match the grid dimensions
77-
let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);
78-
79-
// Transpose the reshapedSolution array to get column-wise data
80-
let transposedSolution = math.transpose(reshapedSolution);
81-
82-
// Create an array for x-coordinates used in the contour plot
83-
let reshapedXForPlot = [];
84-
for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {
85-
let xValue = nodesXCoordinates[i];
86-
reshapedXForPlot.push(xValue);
87-
}
88-
89-
// Create the data structure for the contour plot
90-
let contourData = {
91-
z: transposedSolution,
92-
type: "contour",
93-
contours: {
94-
coloring: "heatmap",
95-
},
96-
x: reshapedXForPlot,
97-
y: reshapedYCoordinates[0],
98-
};
99-
100-
// Create mesh lines for the computational grid if showMesh is true
101-
let meshData = [];
102-
if (showMesh) {
103-
let meshLinesX = [];
104-
let meshLinesY = [];
105-
106-
// Horizontal mesh lines
107-
for (let i = 0; i < numNodesY; i++) {
108-
meshLinesX.push(...reshapedXCoordinates.map((row) => row[i]), null);
109-
meshLinesY.push(...reshapedYCoordinates.map((row) => row[i]), null);
110-
}
111-
112-
// Vertical mesh lines
113-
for (let i = 0; i < numNodesX; i++) {
114-
meshLinesX.push(...reshapedXCoordinates[i], null);
115-
meshLinesY.push(...reshapedYCoordinates[i], null);
116-
}
117-
118-
// Create the data structure for the mesh lines
119-
meshData = {
120-
x: meshLinesX,
121-
y: meshLinesY,
122-
mode: "lines",
123-
type: "scatter",
124-
line: {
125-
color: "palegoldenrod",
126-
width: 1,
127-
},
128-
showlegend: false,
129-
};
130-
}
131-
132-
// Set a fixed maximum window size for the plot
68+
// Use the user-provided mesh type
69+
const isStructured = meshType === "structured";
70+
71+
// For auto-detection (if needed)
72+
const uniqueXCoords = new Set(nodesXCoordinates).size;
73+
const uniqueYCoords = new Set(nodesYCoordinates).size;
74+
75+
// Extract scalar values from solution vector
76+
let zValues = Array.isArray(solutionVector[0])
77+
? solutionVector.map(val => val[0])
78+
: solutionVector;
79+
80+
// Common sizing parameters for both plot types
13381
let maxWindowWidth = Math.min(window.innerWidth, 700);
134-
let maxPlotWidth = Math.max(...reshapedXForPlot);
135-
let maxPlotHeight = Math.max(...reshapedYCoordinates[0]);
136-
let zoomFactor = maxWindowWidth / maxPlotWidth;
137-
let plotWidth = zoomFactor * maxPlotWidth;
138-
let plotHeight = zoomFactor * maxPlotHeight;
139-
140-
// Set the layout for the contour plot
82+
let maxX = Math.max(...nodesXCoordinates);
83+
let maxY = Math.max(...nodesYCoordinates);
84+
let aspectRatio = maxY / maxX;
85+
let plotWidth = Math.min(maxWindowWidth, 600);
86+
let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance
87+
88+
// Common layout properties
14189
let layout = {
142-
title: `${plotType} plot${showMesh ? " with mesh" : ""} - ${solverConfig}`,
90+
title: `${plotType} plot (${meshType}) - ${solverConfig}`,
14391
width: plotWidth,
14492
height: plotHeight,
14593
xaxis: { title: "x" },
14694
yaxis: { title: "y" },
95+
margin: { l: 50, r: 50, t: 50, b: 50 },
96+
hovermode: 'closest'
14797
};
98+
99+
if (isStructured) {
100+
// Calculate the number of nodes along the x-axis and y-axis
101+
const numNodesX = uniqueXCoords;
102+
const numNodesY = uniqueYCoords;
103+
104+
// Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions
105+
let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);
106+
let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);
107+
108+
// Reshape the solution array to match the grid dimensions
109+
let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);
110+
111+
// Transpose the reshapedSolution array to get column-wise data
112+
let transposedSolution = math.transpose(reshapedSolution);
113+
114+
// Create an array for x-coordinates used in the contour plot
115+
let reshapedXForPlot = [];
116+
for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {
117+
let xValue = nodesXCoordinates[i];
118+
reshapedXForPlot.push(xValue);
119+
}
120+
121+
// Create the data structure for the contour plot
122+
let contourData = {
123+
z: transposedSolution,
124+
type: "contour",
125+
contours: {
126+
coloring: "heatmap",
127+
showlabels: true
128+
},
129+
//colorscale: 'Viridis',
130+
colorbar: {
131+
title: 'Solution'
132+
},
133+
x: reshapedXForPlot,
134+
y: reshapedYCoordinates[0],
135+
name: 'Solution Field'
136+
};
148137

149-
// Create the plot using Plotly
150-
let plotData = [contourData];
151-
if (showMesh) {
152-
plotData.push(meshData);
138+
// Create the plot using Plotly
139+
Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });
140+
} else {
141+
// Create an interpolated contour plot for the unstructured mesh
142+
let contourData = {
143+
x: nodesXCoordinates,
144+
y: nodesYCoordinates,
145+
z: zValues,
146+
type: 'contour',
147+
contours: {
148+
coloring: 'heatmap',
149+
showlabels: true
150+
},
151+
//colorscale: 'Viridis',
152+
colorbar: {
153+
title: 'Solution'
154+
},
155+
name: 'Solution Field'
156+
};
157+
158+
// Create the plot using only the contour fill
159+
Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });
153160
}
154-
Plotly.newPlot(plotDivId, plotData, layout, { responsive: true });
155161
}
156162
}

0 commit comments

Comments
 (0)
Please sign in to comment.