---
title: A mesh from Gmsh
summary: Laminar flow past a cylinder in a channel on an unstructured mesh of cubic quadrilaterals written by Gmsh — set up from the mesh's physical groups, solved in Python and through the service, with an adjoint derivative checked against finite differences.
section: examples
order: 6
level: 1
audience: [CFD practitioners, MDO integrators]
keywords: [Gmsh, mesh file, imported mesh, unstructured, cylinder, channel, mesh store, example]
---
<!-- gyre docs: expanded Markdown of examples/imported-mesh.md (generated tables, verification numbers and chart data are written out). Base level of this page: L1 Essentials; passages at another level are bracketed by 'begin level N' / 'end level N' comments and start with [LN Name]. Built from revision ceb1f4b0be. -->

The mesh `examples/meshes/cylinder_channel_p3.msh` is Gmsh output: a channel with a circular
cylinder, meshed with unstructured cubic quadrilaterals and saved as MSH 4.1 ASCII. Its four
physical groups — `cylinder`, `inflow`, `outflow`, `walls` — are the boundary groups of the
case. [Mesh files](../guide/meshes.md) explains how such a file is made and what the reader
requires.

```bash
gyre mesh info examples/meshes/cylinder_channel_p3.msh      # groups, size, quality
python examples/imported_mesh.py                            # solve in this process
python examples/imported_mesh.py http://HOST:8600           # upload the mesh, solve as a job
```

The case: Mach 0.2, Reynolds number 40 (based on the unit diameter), polynomial degree 2, an
adiabatic no-slip cylinder, slip walls, and far-field conditions at the inflow and outflow
sides.

**Verification status: Imported meshes** (study `imported_mesh`): **PASSED**, 29 of 29 checks passed, 184.5 s.

A mesh read from a file must behave exactly like a generated one, including unstructured topology, where neighbouring elements use different local axes. (i) Every Gmsh fixture of the test suite is read; the files are genuine Gmsh output (tools/make_mesh_fixtures.py), and on the straight-sided ones every high-order node must be the multilinear image of the element's vertices, which tests the node-ordering tables for quadrilaterals of degree 1 to 5 and hexahedra of degree 1 to 4. (ii) On curved unstructured meshes from Gmsh in 2-D and 3-D, and on a 3-D mesh whose elements were randomly re-oriented and passed through a file, a uniform flow must remain steady, the residuals of a perturbed state must sum to zero, and the inviscid residual of a continuous state must not depend on the Riemann solver away from the boundary (the jump across every face is zero only if its nodes are matched with the right ones of the neighbour; the viscous terms cancel in this comparison, so it is made for the Euler equations only). The coupling of the viscous terms across faces (gradient traces of the neighbour, lifted jumps) is tested separately, for both sets of equations: a rough state with varying velocity and temperature and a jump on every face must give the same residual, node by node, when every element of the mesh is stored in other, randomly chosen local axes. (iii) The coarse annulus of the cylinder case, written to a Gmsh file after randomly re-orienting its elements and read back through a case specification, must give the force coefficients of the generated mesh to solver tolerance. (iv) Laminar flow past a cylinder in a channel (Re = 40, M = 0.2, slip walls) is solved on the unstructured example mesh at degree 2, and the adjoint derivative of the drag coefficient with respect to the Mach number is compared with a central finite difference of re-converged flows.

| Check | Value | Expected | Result |
|---|---|---|---|
| usable Gmsh fixtures read | 15 of 15 | all | pass |
| unusable Gmsh fixtures (triangles, binary, untagged) refused with a message | 3 of 3 | all | pass |
| straight-sided fixtures cover quadrilaterals of degree 1–5 and hexahedra of degree 1–4 | 9 | = 9 (dimension, degree) pairs | pass |
| node ordering: largest distance of a node of a straight-sided mesh from the multilinear map of its vertices | 4.4409e-15 | < 1e-13 (round-off; coordinates of order one) | pass |
| straight-sided meshes: relative error of the area / volume | 3.0585e-16 | < 1e-12 (the quadrature is exact for multilinear elements) | pass |
| every straight-sided fixture is unstructured: fewest face pairs with a non-identity orientation | 44 | > 0 | pass |
| curved quadrilateral meshes (circular hole): area error at geometry degree pg + 1 relative to pg, largest | 0.147256 | < 1 (the boundary interpolant converges with the degree) | pass |
| MSH 2.2 and MSH 4.1 files of one periodic mesh: largest node difference | 0 | < 1e-12 | pass |
| periodic node pairs of the file became topology (slave nodes) | 13 | > 0, and no boundary group on the periodic sides | pass |
| hole_quad_p3.msh (Gmsh, curved, 2-D), inviscid: perturbed state is not trivial (max \|Rw\|) | 0.415774 | > 1e-3 | pass |
| hole_quad_p3.msh (Gmsh, curved, 2-D), viscous: perturbed state is not trivial (max \|Rw\|) | 0.435898 | > 1e-3 | pass |
| hole_quad_p3.msh (Gmsh, curved, 2-D): face pairs with a non-identity orientation | 48 | > 0 | pass |
| hole_hex_p2.msh (Gmsh, curved, 3-D), inviscid: perturbed state is not trivial (max \|Rw\|) | 0.620272 | > 1e-3 | pass |
| hole_hex_p2.msh (Gmsh, curved, 3-D), viscous: perturbed state is not trivial (max \|Rw\|) | 0.306193 | > 1e-3 | pass |
| hole_hex_p2.msh (Gmsh, curved, 3-D): face pairs with a non-identity orientation | 72 | > 0 | pass |
| periodic warped 3x3x3 box, re-oriented, written and read back, inviscid: perturbed state is not trivial (max \|Rw\|) | 0.115116 | > 1e-3 | pass |
| periodic warped 3x3x3 box, re-oriented, written and read back, viscous: perturbed state is not trivial (max \|Rw\|) | 0.120425 | > 1e-3 | pass |
| periodic warped 3x3x3 box, re-oriented, written and read back: face pairs with a non-identity orientation | 74 | > 0 | pass |
| re-oriented 3-D box read from a file: relative face orientations present | 8 | = 8 (all) | pass |
| free stream on imported meshes: largest max \|Rw\| | 4.4409e-15 | < 1e-12 | pass |
| conservation on imported meshes: largest \|sum of Rw\| of a perturbed state | 1.3767e-14 | < 1e-12 (residuals of order 0.1 to 1) | pass |
| neighbour matching on imported meshes (inviscid): largest \|Rw(Roe) − Rw(LLF)\| off the boundary for a continuous state | 9.9920e-16 | < 1e-12 (zero jump across every correctly matched face; residuals of order 0.1 to 1) | pass |
| neighbour coupling on imported meshes, Euler and Navier–Stokes: largest difference of the residual of a rough state between two descriptions of the mesh (elements re-oriented) | 2.4813e-14 | < 1e-12 (round-off; residuals of order 0.1 to 1) | pass |
| the rough state exercises the viscous terms: smallest max \|Rw(Navier–Stokes) − Rw(Euler)\| | 0.0227105 | > 1e-3 (velocity and temperature vary; far above the bound of the coupling check) | pass |
| generated and imported annulus: both solves converged | yes | true | pass |
| imported annulus: face pairs with a non-identity orientation | 42 | > 0 (elements were re-oriented before writing) | pass |
| force and moment coefficients, \|imported − generated\| (largest) | 2.1316e-14 | < 1e-10 (both solves reduce the residual by 1e-12) | pass |
| cylinder in a channel (examples/meshes/cylinder_channel_p3.msh), Re = 40, p = 2: converged | yes | true | pass |
| cylinder in a channel: dcd/dmach, adjoint vs central finite difference (rel.) | 1.1825e-07 | < 1e-6 | pass |

Run notes: Measured in this run: the largest free-stream residual on the imported meshes was 4.4e-15, the largest conservation defect 1.4e-14 and the largest dependence of the inviscid residual of a continuous state on the Riemann solver 1.0e-15. The residual of a rough state changed by at most 2.5e-14 when the elements were re-oriented, with and without viscous terms; the viscous terms contributed between 2.3e-02 and 1.4e-01 to that residual. Conservation alone would not notice a wrong index map between two straight faces (their normals are constant); the Riemann-solver comparison (trace matching, an inviscid test: the viscous terms cancel in it), the comparison of two descriptions (which includes the gradient traces and lifted jumps of the viscous discretization) and the solves of parts (iii) and (iv) do. The annulus written to a file with re-oriented elements (42 of 84 face pairs with a non-identity orientation) gave force coefficients within 2.1e-14 of those on the generated mesh. On the example mesh the adjoint derivative of the drag coefficient with respect to the Mach number differs from the central difference by a relative 1.2e-07. The Gmsh fixtures contain only two of the eight relative face orientations of hexahedra (see the table); all eight occur in the re-oriented box, which is written by Gyre's own writer, not by Gmsh.

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T11:46:10-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [imported_mesh.json](../data/verification/imported_mesh.json).

The study above covers more than this example (it also reads the Gmsh fixtures of the test
suite and tests the discrete invariants on them); the table below is its part on this mesh.
The complete study is on the page [Imported meshes](../verification/imported-meshes.md).

**Table: Cylinder in a channel on examples/meshes/cylinder_channel_p3.msh** (Imported meshes)

| quantity | value |
|---|---|
| elements | 284 |
| geometry degree | 3 |
| degrees of freedom | 10224 |
| face pairs with a non-identity orientation | 104 of 528 |
| Newton steps | 14 |
| final / reference residual | 7.7014e-13 |
| cd | 3.21039 |
| cl | 2.2180e-04 |
| cm (about the cylinder axis) | -0.00200862 |
| dcd/dmach, adjoint | 0.331089 |
| dcd/dmach, central difference (step 0.0001) | 0.331089 |
| relative difference | 1.1825e-07 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T11:46:10-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [imported_mesh.json](../data/verification/imported_mesh.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] The case, in Python and through the service**

**[Alternative: Python]**

```python
from gyre.cases import CaseSpec
from gyre.meshio import inspect_mesh
from gyre.runner import run_case

mesh = "examples/meshes/cylinder_channel_p3.msh"
print(inspect_mesh(mesh)["boundaries"])          # faces per boundary group

spec = CaseSpec.model_validate({
    "name": "cylinder_channel",
    "mesh": {"generator": "file", "params": {"path": mesh}},
    "flow": {"mach": 0.2, "reynolds": 40.0},
    "discretization": {"order": 2, "boundaries": {
        "cylinder": "noslip_adiabatic", "inflow": "farfield",
        "outflow": "farfield", "walls": "slip_wall"}},
    "reference": {"moment_center": [0.0, 0.0]},
})
result = run_case(spec, gradients={"of": ["cd"], "wrt": ["mach"]})
print(result["converged"], result["outputs"]["cd"],
      result["gradients"]["derivatives"]["cd"]["mach"])
```

**[Alternative: Service]**

```python
from gyre.client import GyreClient

gyre = GyreClient("http://HOST:8600")
info = gyre.upload_mesh("examples/meshes/cylinder_channel_p3.msh")
case = {
    "name": "cylinder_channel",
    "mesh": {"generator": "file", "params": {"path": info["name"]}},   # the stored name
    "flow": {"mach": 0.2, "reynolds": 40.0},
    "discretization": {"order": 2, "boundaries": {
        "cylinder": "noslip_adiabatic", "inflow": "farfield",
        "outflow": "farfield", "walls": "slip_wall"}},
    "reference": {"moment_center": [0.0, 0.0]},
}
print(gyre.validate(case)["estimate"])           # elements, degrees of freedom
result = gyre.run(case, gradients={"of": ["cd"], "wrt": ["mach"]})
```

**[Alternative: curl]**

```bash
API=http://HOST:8600/api/v1
curl -s -X PUT --data-binary @examples/meshes/cylinder_channel_p3.msh \
     -H 'content-type: application/octet-stream' $API/meshes/cylinder_channel_p3.msh
curl -s $API/jobs -H 'content-type: application/json' -d '{
  "case": {"name": "cylinder_channel",
           "mesh": {"generator": "file", "params": {"path": "cylinder_channel_p3.msh"}},
           "flow": {"mach": 0.2, "reynolds": 40.0},
           "discretization": {"order": 2, "boundaries": {
               "cylinder": "noslip_adiabatic", "inflow": "farfield",
               "outflow": "farfield", "walls": "slip_wall"}},
           "reference": {"moment_center": [0.0, 0.0]}},
  "gradients": {"of": ["cd"], "wrt": ["mach"]}}'
```

`examples/imported_mesh.py` is the runnable form of the first two tabs; `--order 1` makes the
solve cheaper. In the process that owns the file the case names a path; a service is given
the name under which the mesh was uploaded and never a path.

<!-- end level 2 -->

<!-- begin level 2 (Practice) -->
**[L2 Practice] What to look for**

* **Every group needs a condition.** A mesh file has no default boundary conditions; leaving
  out `walls`, or naming a group the mesh does not have, is a validation error that lists the
  groups of the mesh.
* **The reference section.** `moment_center` moves the moment reference from the default
  quarter-chord point to the cylinder axis. The diameter is one, so the default reference area
  and length apply.
* **Forces include the slip walls.** The coefficients are integrated over every group with a
  wall condition, here the cylinder and the two channel walls. The channel walls are parallel
  to the flow and carry no shear, so they add nothing to the force in the stream direction;
  they do contribute to `cl` and `cm`.
* **An unstructured mesh.** The table reports how many interior face pairs join elements with
  different local axes; on a generated mesh there are none.
* **The adjoint agrees with finite differences.** The derivative of the drag coefficient with
  respect to the Mach number from one adjoint solve is compared with a central difference of
  two re-converged flows.

<!-- end level 2 -->

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] The same solver on a generated and on an imported mesh**

The study also writes the coarse annulus of the cylinder preset to a Gmsh file, after
re-orienting its elements at random, reads it back through a case specification and solves
both. The force coefficients must agree to solver tolerance:

**Table: Cylinder Re = 40 on the generated annulus (12 x 4, p = 2) and on the same mesh read from a file** (Imported meshes)

| quantity | generated | imported | difference |
|---|---|---|---|
| cd | 1.69824 | 1.69824 | 2.1316e-14 |
| cl | -2.0933e-14 | -2.1852e-14 | 9.1940e-16 |
| cm | -2.8159e-15 | -6.9159e-15 | 4.1000e-15 |
| Newton steps | 13 | 13 | — |
| final / reference residual | 4.0911e-14 | 3.5832e-14 | — |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T11:46:10-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [imported_mesh.json](../data/verification/imported_mesh.json).

**Chart: Residual histories on generated and imported meshes** (Imported meshes). History chart of |Rw| against nonlinear iteration, y axis log; 3 series. The table holds the plotted data. The histories of the generated and of the imported annulus coincide.

| series | nonlinear iteration | \|Rw\| |
|---|---|---|
| annulus, generated | 0 | 28.3595 |
| annulus, generated | 1 | 18.8413 |
| annulus, generated | 2 | 15.4035 |
| annulus, generated | 3 | 5.38765 |
| annulus, generated | 4 | 4.32122 |
| annulus, generated | 5 | 1.04459 |
| annulus, generated | 6 | 0.203824 |
| annulus, generated | 7 | 0.0763292 |
| annulus, generated | 8 | 0.00731001 |
| annulus, generated | 9 | 1.0453e-04 |
| annulus, generated | 10 | 1.0185e-06 |
| annulus, generated | 11 | 8.2949e-09 |
| annulus, generated | 12 | 5.3854e-11 |
| annulus, generated | 13 | 1.1602e-12 |
| annulus, re-oriented and read from a file | 0 | 28.3595 |
| annulus, re-oriented and read from a file | 1 | 18.8413 |
| annulus, re-oriented and read from a file | 2 | 15.4035 |
| annulus, re-oriented and read from a file | 3 | 5.38765 |
| annulus, re-oriented and read from a file | 4 | 4.32122 |
| annulus, re-oriented and read from a file | 5 | 1.04459 |
| annulus, re-oriented and read from a file | 6 | 0.203824 |
| annulus, re-oriented and read from a file | 7 | 0.0763292 |
| annulus, re-oriented and read from a file | 8 | 0.00731001 |
| annulus, re-oriented and read from a file | 9 | 1.0453e-04 |
| annulus, re-oriented and read from a file | 10 | 1.0185e-06 |
| annulus, re-oriented and read from a file | 11 | 8.2949e-09 |
| annulus, re-oriented and read from a file | 12 | 5.3709e-11 |
| annulus, re-oriented and read from a file | 13 | 1.0162e-12 |
| cylinder in a channel (Gmsh mesh) | 0 | 24.7737 |
| cylinder in a channel (Gmsh mesh) | 1 | 13.8753 |
| cylinder in a channel (Gmsh mesh) | 2 | 8.51098 |
| cylinder in a channel (Gmsh mesh) | 3 | 5.12228 |
| cylinder in a channel (Gmsh mesh) | 4 | 3.3529 |
| cylinder in a channel (Gmsh mesh) | 5 | 2.0295 |
| cylinder in a channel (Gmsh mesh) | 6 | 0.910516 |
| cylinder in a channel (Gmsh mesh) | 7 | 0.36902 |
| cylinder in a channel (Gmsh mesh) | 8 | 0.0892722 |
| cylinder in a channel (Gmsh mesh) | 9 | 0.0363698 |
| cylinder in a channel (Gmsh mesh) | 10 | 0.00262342 |
| cylinder in a channel (Gmsh mesh) | 11 | 3.1460e-05 |
| cylinder in a channel (Gmsh mesh) | 12 | 3.0281e-07 |
| cylinder in a channel (Gmsh mesh) | 13 | 2.5325e-09 |
| cylinder in a channel (Gmsh mesh) | 14 | 1.9079e-11 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T11:46:10-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [imported_mesh.json](../data/verification/imported_mesh.json).

`gyre mesh export cylinder_re40 annulus.msh` writes such a file from any preset.

<!-- end level 3 -->
