Skip to content

Commit b1435be

Browse files
committed
Update HeatConduction2DFinGmsh tutorial. Add mesh and image assets for rectangular quadrilateral case.
1 parent 789ced2 commit b1435be

File tree

6 files changed

+1188
-639
lines changed

6 files changed

+1188
-639
lines changed

assets/gmsh_rect_quad.png

14.4 KB
Loading

tutorials/HeatConduction2DFinGmsh.html

Lines changed: 217 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ <h1>Heat Conduction in a Two-Dimensional Fin (Gmsh Example)</h1>
8484

8585
<ul id="menu">
8686
<li><a href="#gmshfileimport">Gmsh File Import</a></li>
87+
<li><a href="#gmshgeofile">Example Gmsh .geo File</a></li>
88+
<li><a href="#generatedmesh">Generated Mesh</a></li>
8789
<li><a href="#results">Results</a></li>
8890
</ul>
8991

@@ -97,9 +99,206 @@ <h1>Heat Conduction in a Two-Dimensional Fin (Gmsh Example)</h1>
9799
</div>
98100

99101
<h2 id="gmshfileimport"><a name="gmshfileimport"></a>Gmsh File Import</h2>
100-
<p>The code below shows how to import a Gmsh (.msh) file and set up the problem.</p>
102+
<p>
103+
This example demonstrates how to import a Gmsh-generated mesh (.msh file format) and solve a heat
104+
conduction problem.
105+
</p>
106+
107+
<p>The key advantages of using Gmsh with FEAScript include:</p>
108+
<ul>
109+
<li>Ability to create complex geometries that would be difficult to define programmatically</li>
110+
<li>Control over mesh refinement in specific regions</li>
111+
<li>Ability to define physical groups that map to boundary conditions</li>
112+
<li>Support for various element types (quadrilaterals and triangles)</li>
113+
</ul>
114+
115+
<p>The code below shows how to import a Gmsh .msh file and set up the problem:</p>
116+
117+
<pre class="prettyprint">
118+
&lt;script type="module"&gt;
119+
import { FEAScriptModel, importGmshQuadTri, plotSolution, printVersion } from "https://core.feascript.com/src/index.js";
120+
121+
window.addEventListener("DOMContentLoaded", async () => {
122+
// Print FEAScript version in the console
123+
printVersion();
124+
125+
// Fetch the mesh file
126+
const response = await fetch("./rect_quad.msh"); // .msh version 4.1 is currently supported
127+
if (!response.ok) {
128+
throw new Error(`Failed to load mesh file: ${response.status} ${response.statusText}`);
129+
}
130+
const meshContent = await response.text();
131+
132+
// Create a File object with the actual content
133+
const meshFile = new File([meshContent], "rect_quad.msh");
134+
135+
// Create a new FEAScript model
136+
const model = new FEAScriptModel();
137+
138+
// Set solver configuration
139+
model.setSolverConfig("solidHeatTransferScript");
140+
141+
// Parse the mesh file first
142+
const result = await importGmshQuadTri(meshFile);
143+
144+
// Define mesh configuration with the parsed result
145+
model.setMeshConfig({
146+
parsedMesh: result,
147+
meshDimension: "2D",
148+
elementOrder: "linear",
149+
});
150+
151+
// Define boundary conditions using Gmsh physical group tags
152+
model.addBoundaryCondition("0", ["constantTemp", 200]); // bottom boundary
153+
model.addBoundaryCondition("1", ["constantTemp", 200]); // right boundary
154+
model.addBoundaryCondition("2", ["convection", 1, 20]); // top boundary
155+
model.addBoundaryCondition("3", ["symmetry"]); // left boundary
156+
157+
// Set solver method
158+
model.setSolverMethod("lusolve");
159+
160+
// Solve the problem and get the solution
161+
const { solutionVector, nodesCoordinates } = model.solve();
162+
163+
// Plot the solution as a 2D contour plot
164+
plotSolution(
165+
solutionVector,
166+
nodesCoordinates,
167+
model.solverConfig,
168+
model.meshConfig.meshDimension,
169+
"contour",
170+
"solutionPlot",
171+
"unstructured" // Important: specify unstructured mesh type
172+
);
173+
});
174+
&lt;/script&gt;</pre
175+
>
176+
177+
<p>
178+
<strong>Important notes about the Gmsh workflow:</strong>
179+
</p>
180+
<ol>
181+
<li>
182+
<strong>Physical Groups in Gmsh:</strong> In your .geo file, you need to define physical groups for
183+
boundaries using commands like <code>Physical Line("bottom") = {1};</code>. These are mapped to tags
184+
in the imported mesh.
185+
</li>
186+
<li>
187+
<strong>Boundary Condition Mapping and Tag Indexing:</strong> When using Gmsh meshes in FEAScript, you
188+
need to subtract 1 from the Gmsh physical group tag numbers. For example, if your Gmsh file has
189+
physical groups with tags 1, 2, 3, and 4, you would reference them in FEAScript as "0", "1", "2", and
190+
"3" respectively:
191+
<code>model.addBoundaryCondition("0", ["constantTemp", 200]); // Gmsh physical group tag 1</code>.
192+
This conversion is necessary because Gmsh uses 1-based indexing while FEAScript uses 0-based indexing.
193+
</li>
194+
<li>
195+
<strong>Unstructured Plotting:</strong> When plotting results from a Gmsh mesh, add the "unstructured"
196+
parameter to the plotSolution function to ensure correct visualization.
197+
</li>
198+
</ol>
199+
200+
<p>
201+
You can create your own Gmsh files by writing .geo scripts or using Gmsh's GUI. For this example, we
202+
used a simple rectangular domain defined in a .geo file with specific physical groups for each boundary.
203+
</p>
204+
205+
<h3 id="gmshgeofile"><a name="gmshgeofile"></a>Example Gmsh .geo File</h3>
206+
<p>
207+
Below is the <code>rect.geo</code> file used in this tutorial. It defines a 4m × 2m rectangular domain
208+
with physical lines for each boundary edge:
209+
</p>
210+
211+
<pre class="prettyprint">
212+
// 2D Rectangle: 4m (width) x 2m (height)
213+
// With Physical Lines for boundary labeling
214+
// Use the command "gmsh rect.geo -2" to generate the mesh
215+
216+
lc = 0.2; // Characteristic length (mesh density)
217+
218+
// Points (x, y, z, mesh size)
219+
Point(1) = {0, 0, 0, lc}; // Bottom left
220+
Point(2) = {4, 0, 0, lc}; // Bottom right
221+
Point(3) = {4, 2, 0, lc}; // Top right
222+
Point(4) = {0, 2, 0, lc}; // Top left
223+
224+
// Lines
225+
Line(1) = {1, 2}; // bottom
226+
Line(2) = {2, 3}; // right
227+
Line(3) = {3, 4}; // top
228+
Line(4) = {4, 1}; // left
229+
230+
// Line Loop and Surface
231+
Line Loop(1) = {1, 2, 3, 4};
232+
Plane Surface(1) = {1};
233+
234+
// Physical Lines
235+
Physical Line("bottom") = {1};
236+
Physical Line("right") = {2};
237+
Physical Line("top") = {3};
238+
Physical Line("left") = {4};
239+
240+
// Physical Surface (optional, for FEM domains)
241+
Physical Surface("domain") = {1};
242+
243+
// Generate 2D mesh
244+
Recombine Surface{1}; // Turns triangle mesh into quads
245+
Mesh 2;
246+
</pre>
247+
248+
<p>
249+
Note how the physical line tags in the geo file correspond to the boundary conditions in our FEAScript
250+
code:
251+
</p>
252+
<ul>
253+
<li>
254+
<code>Physical Line("bottom") = {1};</code>
255+
<code>model.addBoundaryCondition("0", ["constantTemp", 200]);</code>
256+
</li>
257+
<li>
258+
<code>Physical Line("right") = {2};</code>
259+
<code>model.addBoundaryCondition("1", ["constantTemp", 200]);</code>
260+
</li>
261+
<li>
262+
<code>Physical Line("top") = {3};</code>
263+
<code>model.addBoundaryCondition("2", ["convection", 1, 20]);</code>
264+
</li>
265+
<li>
266+
<code>Physical Line("left") = {4};</code>
267+
<code>model.addBoundaryCondition("3", ["symmetry"]);</code>
268+
</li>
269+
</ul>
270+
271+
<p>
272+
To generate a mesh file from this .geo script, you would run: <code>gmsh rect.geo -2</code> in your
273+
terminal, which creates a rect.msh file that can be imported into FEAScript.
274+
</p>
275+
276+
<h2 id="generatedmesh"><a name="generatedmesh"></a>Generated Mesh</h2>
277+
<p>
278+
Below is a visualization of the quadrilateral mesh generated by Gmsh. Notice how Gmsh creates an
279+
unstructured mesh with irregular elements that could potentially adapt to complex domain features.
280+
</p>
281+
282+
<div class="center-image">
283+
<img
284+
src="../assets/gmsh_rect_quad.png"
285+
alt="Quadrilateral mesh generated by Gmsh"
286+
style="max-width: 80%; height: auto"
287+
/>
288+
<p><em>Figure: Quadrilateral mesh generated using the rect.geo script with Gmsh</em></p>
289+
</div>
290+
291+
<p>
292+
The mesh consists of quadrilateral elements with varying sizes and shapes. This unstructured mesh
293+
approach would be particularly advantageous for complex geometries. FEAScript's Gmsh reader properly
294+
handles this unstructured mesh format and maps the elements and boundary conditions.
295+
</p>
101296

102297
<h2 id="results"><a name="results"></a>Results</h2>
298+
<p>
299+
Below is the 2D contour plot of the computed temperature distribution. This plot is generated in real
300+
time using FEAScript.
301+
</p>
103302

104303
<div id="solutionPlot"></div>
105304

@@ -116,21 +315,25 @@ <h2 id="results"><a name="results"></a>Results</h2>
116315

117316
<script type="module">
118317
// Import FEAScript library from GitHub
119-
//import { FEAScriptModel, importGmshQuadTri, plotSolution, printVersion } from "https://core.feascript.com/src/index.js";
120-
// Import FEAScript library from a local directory
121318
import {
122319
FEAScriptModel,
123320
importGmshQuadTri,
124321
plotSolution,
125322
printVersion,
126-
} from "../../FEAScript-core/src/index.js";
323+
} from "https://core.feascript.com/src/index.js";
324+
// Import FEAScript library from a local directory
325+
//import {
326+
// FEAScriptModel,
327+
// importGmshQuadTri,
328+
// plotSolution,
329+
// printVersion,
330+
//} from "../../FEAScript-core/src/index.js";
127331

128332
window.addEventListener("DOMContentLoaded", async () => {
129333
// Print FEAScript version in the console
130334
printVersion();
131335

132-
console.log("-------- GMSH MESH APPROACH --------");
133-
// Fetch the mesh file from your server
336+
// Fetch the mesh file
134337
const response = await fetch("./rect_quad.msh");
135338
if (!response.ok) {
136339
throw new Error(`Failed to load mesh file: ${response.status} ${response.statusText}`);
@@ -149,11 +352,9 @@ <h2 id="results"><a name="results"></a>Results</h2>
149352
// Parse the mesh file first
150353
const result = await importGmshQuadTri(meshFile);
151354

152-
console.log("GMSH Boundary Conditions:", result.boundaryConditions);
153-
console.log("GMSH Boundary Elements:", result.boundaryElements);
154-
console.log("GMSH Nodal Numbering:", result.nodalNumbering);
155-
console.log("x Coordinates:", result.nodesXCoordinates);
156-
console.log("y Coordinates:", result.nodesYCoordinates);
355+
//console.log("GMSH Nodal Numbering:", result.nodalNumbering);
356+
//console.log("x Coordinates:", result.nodesXCoordinates);
357+
//console.log("y Coordinates:", result.nodesYCoordinates);
157358

158359
// Define mesh configuration with the parsed result
159360
gmshModel.setMeshConfig({
@@ -165,19 +366,20 @@ <h2 id="results"><a name="results"></a>Results</h2>
165366
// Define boundary conditions using Gmsh physical group tags
166367
gmshModel.addBoundaryCondition("0", ["constantTemp", 200]); // bottom boundary
167368
gmshModel.addBoundaryCondition("1", ["constantTemp", 200]); // right boundary
168-
gmshModel.addBoundaryCondition("2", ["constantTemp", 100]); // top boundary
369+
gmshModel.addBoundaryCondition("2", ["convection", 1, 20]); // top boundary
169370
gmshModel.addBoundaryCondition("3", ["symmetry"]); // left boundary
170371

171-
console.log("GMSH Boundary Conditions:", gmshModel.boundaryConditions);
372+
//console.log("GMSH Boundary Conditions:", gmshModel.boundaryConditions);
172373

173374
// Set solver method
174375
//model.setSolverMethod("jacobi");
175376
gmshModel.setSolverMethod("lusolve");
176377

177378
// Solve the problem and get the solution
178-
const { solutionVector: gmshSolutionVector, nodesCoordinates: gmshNodesCoordinates } = gmshModel.solve();
379+
const { solutionVector: gmshSolutionVector, nodesCoordinates: gmshNodesCoordinates } =
380+
gmshModel.solve();
179381

180-
console.log("GMSH Solution Vector:", gmshSolutionVector);
382+
//console.log("GMSH Solution Vector:", gmshSolutionVector);
181383

182384
// Plot the GMSH solution
183385
plotSolution(
@@ -189,39 +391,6 @@ <h2 id="results"><a name="results"></a>Results</h2>
189391
"solutionPlot",
190392
"unstructured"
191393
);
192-
193-
console.log("-------- GEOMETRY MESH APPROACH --------");
194-
// Create a new FEAScript model for the geometry-based mesh
195-
const geoModel = new FEAScriptModel();
196-
197-
// Set solver configuration
198-
geoModel.setSolverConfig("solidHeatTransferScript");
199-
200-
// Define mesh configuration using geometry
201-
geoModel.setMeshConfig({
202-
meshDimension: "2D",
203-
elementOrder: "quadratic",
204-
numElementsX: 8,
205-
numElementsY: 4,
206-
maxX: 4,
207-
maxY: 2,
208-
});
209-
210-
// Define boundary conditions - equivalent to the GMSH setup
211-
geoModel.addBoundaryCondition("0", ["constantTemp", 200]); // bottom boundary
212-
geoModel.addBoundaryCondition("1", ["symmetry"]); // left boundary
213-
geoModel.addBoundaryCondition("2", ["convection", 1, 20]); // top boundary
214-
geoModel.addBoundaryCondition("3", ["constantTemp", 200]); // right boundary
215-
216-
console.log("GEO Boundary Conditions:", geoModel.boundaryConditions);
217-
218-
// Set solver method
219-
//model.setSolverMethod("jacobi");
220-
geoModel.setSolverMethod("lusolve");
221-
222-
// Solve the problem and get the solution
223-
const { solutionVector: geoSolutionVector, nodesCoordinates: geoNodesCoordinates } = geoModel.solve();
224-
225394
});
226395
</script>
227396

tutorials/rect.geo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// With Physical Lines for boundary labeling
33
// Use the command "gmsh rect.geo -2" to generate the mesh
44

5-
lc = 0.3; // Characteristic length (mesh density)
5+
lc = 0.2; // Characteristic length (mesh density)
66

77
// Points (x, y, z, mesh size)
88
Point(1) = {0, 0, 0, lc}; // Bottom left

0 commit comments

Comments
 (0)