@@ -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+ <script type="module">
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+ </script></ 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
0 commit comments