Feature Request: Python API for High-Order Curving of Externally Imported Meshes
Summary
I would like to use hexahedral (hex) high-order elements in NGSolve for improved accuracy in FEM simulations. Since Netgen does not generate hex meshes, I need to import meshes from external mesh generators. However, I discovered that mesh.Curve(order) does not work correctly with externally imported meshes (order ≥ 2).
I would like to request a Python API that enables proper high-order curving for meshes imported from external sources.
Motivation: Hexahedral High-Order Elements
Hex elements offer several advantages over tetrahedral elements:
- Better accuracy per degree of freedom
- More efficient for structured geometries
- Required for certain physics (e.g., large deformation, incompressibility)
To use hex meshes in NGSolve, I need to:
- Generate hex mesh in an external mesh generator
- Import the mesh into NGSolve
- Apply high-order curving for curved boundaries
Step 3 is currently problematic.
Problem Description
Current Behavior
When importing meshes from external sources, mesh.Curve(order) produces incorrect results for order ≥ 2:
| Method | Area Error | Volume Error |
|-------------------------------|-----------|--------------|
| Pure Netgen + Curve(4) | 0.000003% | 0.000004% |
| External mesh + Curve(2) | ~56% | ~6% |
| External mesh + Curve(3) | ~64% | ~8% |
| External mesh + Curve(4) | ~69% | ~9% |
Root Cause
mesh.Curve(order) requires Element2D.geominfo which contains UV parametric coordinates (surfnr, u, v). These UV parameters are only set when Netgen generates the mesh directly. When importing meshes from external sources, geominfo is not populated, causing Curve(2+) to produce incorrect (inflated) results.
Current Workaround: SetDeformation
I am currently using SetDeformation to manually project boundary elements onto the exact geometry:
from ngsolve import VectorH1, GridFunction, CF, sqrt, x, y, IfPos, Mesh
from netgen.occ import OCCGeometry
# Import external mesh and attach OCC geometry
ngmesh = import_external_mesh(...) # Custom import function
ngmesh.SetGeometry(occ_geometry)
mesh = Mesh(ngmesh)
mesh.Curve(1) # Linear mesh ONLY
# Apply SetDeformation for cylinder surface (radius R)
fes = VectorH1(mesh, order=4)
deform = GridFunction(fes)
r_xy = sqrt(x*x + y*y)
scale = IfPos(r_xy - 0.01, R/r_xy - 1, 0)
deform.Set(CF((scale*x, scale*y, 0)), definedon=mesh.Boundaries('cylinder_surface'))
mesh.SetDeformation(deform)
Results with SetDeformation
| Method | Area Error | Volume Error |
|-------------------------------------|-------------|--------------|
| Pure Netgen + Curve(4) | 0.000003% | 0.000004% |
| External mesh + SetDeformation(4) | 0.000044% | 0.000065% |
| External mesh + SetDeformation(6) | 0.000000% | 0.000000% |
SetDeformation achieves excellent accuracy, but:
- Requires manual implementation for each geometry type (cylinder, sphere, cone, torus, etc.)
- Cannot handle arbitrary CAD geometry automatically
- The mesh visually appears as 1st-order elements (deformation is applied at integration level)
Feature Request
Option 1: API to Set geominfo for External Meshes
Provide a Python API to set Element2D.geominfo for boundary elements:
# Proposed API
for el in ngmesh.Elements2D():
# Compute UV coordinates from OCC geometry
face = geo.GetFace(el.surfnr)
u, v = face.GetUV(el.center)
el.SetGeomInfo(surfnr=el.surfnr, u=u, v=v)
mesh = Mesh(ngmesh)
mesh.Curve(4) # Now works correctly
Option 2: Alternative Curving Method Without geominfo
Provide a method that curves the mesh by projecting boundary nodes directly onto the OCC geometry surface, without requiring UV parameters:
# Proposed API
mesh.CurveFromGeometry(geo, order=4) # Projects boundary nodes onto geo surfaces
Option 3: Enhanced Mesh Import with Geometry Binding
Provide an import method that properly binds external mesh vertices to OCC geometry and computes geominfo automatically:
# Proposed API
from netgen import ImportExternalMesh
ngmesh = ImportExternalMesh(
vertices=node_coords,
elements3d=hex_connectivity, # or tet, wedge, pyramid
elements2d=quad_connectivity, # or tri
geometry=occ_geometry,
compute_geominfo=True # Automatically compute UV parameters
)
mesh = Mesh(ngmesh)
mesh.Curve(4) # Works correctly
Minimal Test Case
from netgen import occ
from netgen.occ import OCCGeometry
from ngsolve import Mesh, Integrate, CF, BND
import math
# Create cylinder geometry
R, H = 0.5, 2.0
cyl = occ.Cylinder(occ.Pnt(0, 0, -1), occ.Vec(0, 0, 1), r=R, h=H)
geo = OCCGeometry(cyl)
# Generate mesh with Netgen (works correctly)
ngmesh = geo.GenerateMesh(maxh=0.2)
mesh = Mesh(ngmesh)
expected_area = 2*math.pi*R*H + 2*math.pi*R*R
print("Netgen-generated mesh:")
for order in [1, 2, 3, 4]:
mesh.Curve(order)
area = Integrate(CF(1), mesh, VOL_or_BND=BND)
error = abs(area - expected_area) / expected_area * 100
print(f" Curve({order}): Area error = {error:.4f}%")
# Output:
# Curve(1): Area error = 0.5630%
# Curve(2): Area error = 0.0034%
# Curve(3): Area error = 0.0003%
# Curve(4): Area error = 0.0000%
When the same geometry is meshed externally and imported (even attaching the same OCC geometry), Curve(2+) produces 50-70% errors because geominfo is not set.
Use Cases
This feature would enable:
- Hex mesh support: Use external mesh generators for hex meshing, then apply high-order curving in NGSolve
- Complex CAD workflows: Import meshes from industrial CAD/CAE software with proper curved boundary representation
- Hybrid element types: Mixed hex/tet/wedge/pyramid meshes with high-order curving
- Legacy mesh reuse: Apply high-order curving to existing mesh libraries
Environment
- NGSolve version: 6.2.2404
- Python version: 3.12
- OS: Windows 10/11
Thank you for considering this feature request. High-order hex elements would significantly expand NGSolve’s capabilities for industrial and research applications.