Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/KarypisLab/METIS/llms.txt

Use this file to discover all available pages before exploring further.

The METIS mesh file format describes a finite element mesh as a list of elements, where each element is defined by its constituent nodes. This format is consumed by the mpmetis and m2gmetis command-line programs (via ReadMesh in programs/io.c) and corresponds directly to the eptr/eind arrays used in the C API functions METIS_PartMeshDual, METIS_PartMeshNodal, METIS_MeshToDual, and METIS_MeshToNodal. Unlike the graph file format, the mesh file does not encode connectivity between elements—METIS derives that connectivity internally.

Header line

The first non-comment line of the mesh file contains one or two integers:
ne [ncon]
FieldMeaning
neNumber of elements in the mesh
nconOptional number of element-weight constraints (default 1)
Lines starting with % are treated as comments and skipped. The number of nodes (nn) is not stored explicitly in the header; METIS infers it from the maximum node ID seen across all element lines.
The mesh file format does not include an explicit etype (element type) field in the header, unlike what the manual describes for older versions. The current ReadMesh implementation in METIS 5 reads the header as ne [ncon] and derives element type from the node count per element line.

Element lines

After the header, there is exactly one line per element, from element 1 to element ne. Each line contains:
[ewgt_1 ... ewgt_ncon] node_1 node_2 ... node_k
  • If ncon > 0, each line starts with ncon integer element weights.
  • Following the weights (or at the start of the line if ncon == 0) are the 1-based node IDs that form the element.
  • The number of nodes per line determines the element type implicitly.
Common element types and their node counts:
Element typeNodes per elementetype constant
Triangle31
Tetrahedron42
Hexahedron83
Quadrilateral44
All nodes in the file use 1-based numbering (the API uses 0-based internally; ReadMesh converts by subtracting 1 from each node ID).

Example: metis.mesh

The file graphs/metis.mesh is a triangulation of the word “METIS” (7,434 triangular elements). The first few lines are:
7434
 3708 57 2094
 25 308 2956
 2411 1300 2468
 1246 3012 3401
 3765 920 2854
 54 613 3240
 89 2428 4
 544 545 2198
  • Header: 7434 elements, no explicit ncon field (defaults to 0, treated as 1 internally).
  • Each element line contains exactly 3 node IDs, making every element a triangle.
  • Element 1 uses nodes 3708, 57, and 2094.
  • Element 2 uses nodes 25, 308, and 2956.
To partition this mesh into 4 parts:
mpmetis graphs/metis.mesh 4

In-memory eptr/eind arrays

The mesh file maps to two CSR arrays in the C API:
File conceptC API arraySize
Element start offsetseptrne + 1
All node IDs (0-based), concatenatedeindtotal nodes across all elements
eptr[i] is the index into eind where the node list of element i begins. The nodes of element i are eind[eptr[i]] through eind[eptr[i+1] - 1]. This is the same CSR pattern used for xadj/adjncy in graph representation. For a pure triangular mesh with ne elements, eptr and eind look like:
/* 5-element triangular mesh, 0-based node IDs */
idx_t ne   = 5;
idx_t eptr[] = {0, 3, 6, 9, 12, 15};     /* ne+1 entries */
idx_t eind[] = {0, 1, 4,                  /* element 0 */
                1, 2, 4,                  /* element 1 */
                2, 3, 5,                  /* element 2 */
                3, 4, 5,                  /* element 3 */
                4, 5, 6};                 /* element 4 */
The ReadMesh function in programs/io.c fills these arrays directly. When calling the API without file I/O, you construct eptr and eind manually. The total length of eind equals eptr[ne], which is the total number of node references across all elements.

Dual graph vs nodal graph

METIS can derive two different graphs from the same mesh:
In the dual graph, each element becomes a vertex. Two element-vertices are connected by an edge if they share at least ncommon nodes. The dual graph is used when you want to assign entire elements to processors (each element belongs to exactly one partition).
idx_t ncommon = 2; /* triangles: share an edge (2 nodes) */
idx_t numflag = 0;
idx_t *xadj, *adjncy;

METIS_MeshToDual(&ne, &nn, eptr, eind,
                 &ncommon, &numflag, &xadj, &adjncy);
For triangular meshes, ncommon = 2 means two triangles are adjacent if they share an edge (2 nodes). For tetrahedral meshes, use ncommon = 3 to connect tetrahedra that share a face.

The ncommon parameter

ncommon controls how many nodes two elements must share to be considered adjacent in the dual graph. It is passed to METIS_MeshToDual and METIS_PartMeshDual. Typical values by element type:
Element typeTypical ncommonAdjacency semantics
Triangle (3 nodes)2Adjacent if sharing an edge
Tetrahedron (4 nodes)3Adjacent if sharing a face
Hexahedron (8 nodes)4Adjacent if sharing a face
Quadrilateral (4 nodes)2Adjacent if sharing an edge
Setting ncommon = 1 makes two elements adjacent if they share any single node (corner adjacency). Setting ncommon equal to the full element size connects only identical elements, which is rarely useful.
ncommon must be at least 1. The implementation in mesh.c enforces this by clamping smaller values to 1. Choosing too small a value (such as 1 for triangular meshes) produces a denser dual graph with more edges, which can degrade partitioning quality and increase runtime.

Partitioning a mesh directly

METIS_PartMeshDual and METIS_PartMeshNodal partition a mesh without requiring you to construct the dual or nodal graph explicitly:
/* For metis.mesh: 7434 elements, determined by scanning node IDs in the file */
idx_t ne = 7434, nn = 4710; /* nn = max node ID seen across all elements + 1 */
idx_t nparts = 4;
idx_t ncommon = 2;
idx_t objval;
idx_t *epart = malloc(ne * sizeof(idx_t));
idx_t *npart = malloc(nn * sizeof(idx_t));

idx_t options[METIS_NOPTIONS];
METIS_SetDefaultOptions(options);

/* eptr and eind built from reading the mesh file */
METIS_PartMeshDual(&ne, &nn, eptr, eind,
                   NULL,    /* vwgt: uniform element weights */
                   NULL,    /* vsize: uniform sizes */
                   &ncommon, &nparts,
                   NULL,    /* tpwgts: equal partition weights */
                   options,
                   &objval, epart, npart);
On return, epart[i] holds the partition number (0-based) for element i, and npart[j] holds the partition number for node j.

Build docs developers (and LLMs) love