diff --git a/test/tutorials/01_fundamentals/reading_gmsh_meshes.jl b/test/tutorials/01_fundamentals/reading_gmsh_meshes.jl deleted file mode 100644 index 8b62239..0000000 --- a/test/tutorials/01_fundamentals/reading_gmsh_meshes.jl +++ /dev/null @@ -1,195 +0,0 @@ -# # Tutorial 2: Reading Meshes with Gmsh -# -# Real FEM problems need meshes with many elements. Creating them manually -# would be tedious! This tutorial shows how to: -# - Read mesh files generated by Gmsh -# - Extract nodes and elements -# - Organize elements by physical groups (for boundary conditions) -# -# ## Prerequisites -# -# - Tutorial 1 (Creating Elements and Fields) -# - Basic understanding of mesh concepts (nodes, elements, connectivity) - -using JuliaFEM -using Gmsh # Mesh generation and reading -using Test - -# ## The Mesh File -# -# We're reading a pre-generated mesh file: `reading_gmsh_meshes.msh` -# -# This mesh was created using the Gmsh.jl recipe in `reading_gmsh_meshes_recipe.jl`. -# The recipe shows how to programmatically generate meshes - very useful for -# parametric studies! -# -# **Mesh specifications:** -# - Domain: Unit square [0,1] × [0,1] -# - Elements: 10 Quad4 elements (2×5 structured mesh) -# - Nodes: 18 nodes -# - Physical groups: DOMAIN (volume), BOTTOM/RIGHT/TOP/LEFT (boundaries) - -mesh_file = joinpath(@__DIR__, "reading_gmsh_meshes.msh") - -# ## Reading the Mesh with Gmsh.jl -# -# Gmsh.jl provides a Julia interface to the Gmsh API. We can read mesh files -# and extract all the data we need. - -# Initialize Gmsh -gmsh.initialize() - -# Open and read the mesh file -gmsh.open(mesh_file) - -# ## Extracting Nodes -# -# Nodes are the points in space where we'll compute field values. -# In Gmsh, nodes are returned as: -# - `nodeTags`: Node IDs (integers) -# - `coord`: Coordinates (x, y, z) as a flat vector - -nodeTags, coord, parametricCoord = gmsh.model.mesh.getNodes() - -# The `coord` vector is flat: [x1, y1, z1, x2, y2, z2, ...] -# Let's reshape it into a more convenient format: - -num_nodes = length(nodeTags) -nodes = Dict{Int,Vector{Float64}}() - -for i in 1:num_nodes - node_id = nodeTags[i] - x = coord[3*(i-1)+1] - y = coord[3*(i-1)+2] - z = coord[3*(i-1)+3] - nodes[node_id] = [x, y, z] -end - -# Now we have a dictionary mapping node IDs to coordinates! - -# ## Extracting Elements -# -# Elements connect nodes and define the interpolation within each region. -# In Gmsh, we need to query elements by entity (surfaces, volumes, etc.). - -# Get all 2D entities (surfaces in our case) -entities = gmsh.model.getEntities(2) # 2 = dimension for surfaces - -# For each entity, get the elements -all_elements = Element[] - -for entity in entities - dim, tag = entity - - # Get element data for this entity - elemTypes, elemTags, nodeTags_elem = gmsh.model.mesh.getElements(dim, tag) - - # Loop over element types (we have Quad4 = type 3) - for (elemType, elemTag, elemNodeTags) in zip(elemTypes, elemTags, nodeTags_elem) - - # Get element properties - elemName, elemDim, order, numNodes, localNodeCoord, numPrimaryNodes = - gmsh.model.mesh.getElementProperties(elemType) - - # Create JuliaFEM elements - for i in 1:length(elemTag) - # Extract connectivity for this element - start_idx = (i - 1) * numNodes + 1 - end_idx = i * numNodes - # Convert UInt64 to Int for JuliaFEM compatibility - connectivity = Tuple(Int(tag) for tag in elemNodeTags[start_idx:end_idx]) - - # Map Gmsh element type to JuliaFEM element type - if elemType == 3 # Gmsh Quad4 - local elem = Element(Quad4, connectivity) - else - @warn "Unknown element type: $elemType ($elemName)" - continue - end - - # Add geometry field - update!(elem, "geometry", nodes) - - push!(all_elements, elem) - end - end -end - -# ## Physical Groups -# -# Physical groups let us organize elements by region (for materials) -# and boundaries (for boundary conditions). - -# Get all physical groups -physicalGroups = gmsh.model.getPhysicalGroups() - -# We can query which elements belong to each physical group -# (This would be used to create separate Problems for different regions) - -# ## Cleanup -gmsh.finalize() - -# ## Validation Tests -# -# Let's verify the mesh was read correctly: - -@testset "Gmsh Mesh Reading" begin - # Correct number of nodes (2×5 structured quad mesh has 3×6 nodes) - @test length(nodes) == 18 - - # Correct number of elements (2 × 5 = 10 quads) - @test length(all_elements) == 10 - - # All elements should be Quad4 - @test all(e -> typeof(e.properties) == Quad4, all_elements) - - # Node coordinates should be in [0,1] × [0,1] - for (node_id, coord) in nodes - @test 0.0 <= coord[1] <= 1.0 # x ∈ [0,1] - @test 0.0 <= coord[2] <= 1.0 # y ∈ [0,1] - @test coord[3] == 0.0 # z = 0 (2D mesh) - end - - # Each element should have 4 nodes - for element in all_elements - @test length(element.connectivity) == 4 - end -end - -# ## What We Learned -# -# ✅ How to read Gmsh .msh files using Gmsh.jl -# ✅ Extract nodes (IDs and coordinates) -# ✅ Extract elements (type, connectivity) -# ✅ Map Gmsh element types to JuliaFEM types -# ✅ Physical groups organize elements for BCs and materials -# ✅ Mesh generation recipes document mesh creation -# -# ## Why This Approach? -# -# **Pre-generated mesh files** (not generating in tests): -# - Tests are reliable (don't fail due to mesh generation) -# - Tests run faster (no mesh generation overhead) -# - Mesh is version-controlled (reproducible) -# -# **Recipe files** (showing how mesh was made): -# - Educational (teach Gmsh.jl) -# - Documented (can regenerate if needed) -# - Transparent (know exactly what the mesh is) -# -# ## Next Steps -# -# - **Tutorial 3:** Basis functions and shape function evaluation -# - **Tutorial 4:** Solving 1D elasticity (1-element validation) -# - **Tutorial 5:** Solving 2D elasticity (realistic 10-element problem) -# -# ## Real-World Impact -# -# JuliaFEM is being used to **validate other FEM software**! -# See [Issue #265](https://github.com/JuliaFEM/JuliaFEM.jl/issues/265) where -# a user validated their FEM code against JuliaFEM results. This is beautiful - -# we're useful as a reference implementation even after years! -# -# That's why we include **1-element validation tests** with analytical solutions -# and **nice round numbers** (parameters chosen so results are integers). Makes -# it easy to verify by hand calculation or compare with other codes.