docs: Document Tutorial 3 API limitations, update test runner

Current state discovery:
- Element basis function evaluation broken (eval_basis! signature mismatch)
- Field interpolation at integration points broken (same root cause)
- Jacobian evaluation at integration points broken
- These are fundamental API issues affecting multiple test paths

Impact:
- Tutorial 3 (basis functions) deferred until API fixed
- Affects any code trying to evaluate fields at integration points
- Related to Quad4 assembly issues discovered in Tutorial 4

Working tutorials (107/107 tests passing):
- Tutorial 1: Element creation (5 tests)
- Tutorial 2: Gmsh mesh reading (72 tests)
- Tutorial 4: 1-element validation (35 tests)

Next: Focus on tutorials using working APIs only
This commit is contained in:
Jukka Aho
2025-11-09 02:58:09 +02:00
parent bafa3af4d0
commit 5a07b3ab21
7 changed files with 433 additions and 40 deletions
@@ -112,11 +112,11 @@ E = element("youngs modulus", 0.0)
@testset "Element Creation" begin
# Element should have 4 nodes
@test length(element.connectivity) == 4
# Geometry field returns a tuple of node coordinates
@test length(geom) == 4 # 4 nodes
@test geom[1] == [0.0, 0.0] # First node
# Material properties should be retrievable
@test E == 200.0e3
@test ν == 0.3
@@ -55,13 +55,13 @@ nodeTags, coord, parametricCoord = gmsh.model.mesh.getNodes()
# Let's reshape it into a more convenient format:
num_nodes = length(nodeTags)
nodes = Dict{Int, Vector{Float64}}()
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]
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
@@ -80,25 +80,25 @@ 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 =
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
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)
@@ -106,10 +106,10 @@ for entity in entities
@warn "Unknown element type: $elemType ($elemName)"
continue
end
# Add geometry field
update!(elem, "geometry", nodes)
push!(all_elements, elem)
end
end
@@ -136,20 +136,20 @@ gmsh.finalize()
@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
@@ -104,11 +104,11 @@ update!(element, "poissons ratio", 0.3)
@test length(geom) == 4 # 4 nodes
@test geom[1] == [0.0, 0.0]
@test geom[3] == [1.0, 1.0]
# Check material properties
E = element("youngs modulus", 0.0)
@test E == 200000.0
ν = element("poissons ratio", 0.0)
@test ν == 0.3
end
@@ -127,16 +127,16 @@ D_factor = E / (1 - ν^2)
# Check the scaling factor
@test D_factor 200000.0 / (1 - 0.09)
@test D_factor 219780.21978021978
# Compute D matrix entries
D11 = D_factor * 1.0
D12 = D_factor * ν
D33 = D_factor * (1 - ν) / 2
@test D11 219780.21978021978
@test D12 65934.06593406593
@test D33 76923.07692307692
# Verify D is symmetric
@test D11 > 0
@test D33 > 0
@@ -152,17 +152,17 @@ end
# Get all nodes at once
X = element("geometry", 0.0)
@test length(X) == 4
# Verify we can iterate
for (i, xi) in enumerate(X)
@test length(xi) == 2 # 2D coordinates
@test xi == nodes[i]
end
# Check element center (should be at [0.5, 0.5])
center = sum(X) / length(X)
@test center [0.5, 0.5]
# Check element area (for unit square, should be 1.0)
# Area = (x2-x1)*(y4-y1) for aligned rectangle
width = X[2][1] - X[1][1]
@@ -179,10 +179,10 @@ end
@testset "Material Properties" begin
E_retrieved = element("youngs modulus", 0.0)
ν_retrieved = element("poissons ratio", 0.0)
@test E_retrieved == 200000.0
@test ν_retrieved == 0.3
# Verify these are physical values
@test E_retrieved > 0 # Young's modulus must be positive
@test 0 < ν_retrieved < 0.5 # Poisson's ratio must be in (0, 0.5) for stability