io¶
io.writer¶
Export / generic-view free functions for a HexMesh.
- nekmeshpy.io.writer.BCArg¶
a ready
BoundaryConditions, a{name: code}table (each value aBCSpec) standing for its velocity field alone, orNone.- Type:
What
bc=accepts
alias of
BoundaryConditions|Mapping[str,str|int|tuple[str|None,int|None] |Mapping[str,str|int|tuple[str|None,int|None] |None]] |None
- nekmeshpy.io.writer.PeriodicArg¶
the specs, or a pairing already resolved by
hexmesh.periodic_pairs.- Type:
What
to_re2’speriodic=accepts
alias of
Sequence[Periodic] |PeriodicPairs|None
- nekmeshpy.io.writer.FluidArg¶
region name(s), a ready boolean mask, an array of element ids, or
None– seecore.selection.mask_for_selection, which resolves it.- Type:
What
to_re2’sfluid=accepts
alias of
str|Sequence[str] |NDArray[str_] |NDArray[bool] |NDArray[int64] |Sequence[int] |None
- nekmeshpy.io.writer.to_mesh(mesh, bc=None)[source]¶
Return a shared-point
Mesh: welded points,hexahedroncells, and onequadboundary cell per tagged face grouped into namedcell_sets.
- nekmeshpy.io.writer.write(mesh, path, file_format=None, *, bc=None)[source]¶
Write through meshio to any supported format; for native Nek use
to_re2.
- nekmeshpy.io.writer.PERIODIC_CODE = 'P '¶
The Nek BC code for a periodic face. Unlike every other code, it is not a statement the
bctable can make on its own – a'P'row also has to say which element and face it is periodic with, which is whatperiodic=supplies.
- nekmeshpy.io.writer.to_re2(mesh, filename, *, bc, periodic=None, fluid=None)[source]¶
Write the binary Nek
.re2tofilename(the full name, extension included – nothing is appended). The mesh is written linear at any order: Nek’s re2 has no high-order format, so only the 8 corners of each hex are emitted.bcis required: this is the one writer that emits Nek BC codes, and a default would put a code the caller never chose in front of the solver. It is where a mesher states what its named surfaces physically are, so it belongs in the mesher, visible next to the tags it names. ABoundaryConditionscarries one table per field; a plain{name: code}mapping is its velocity table alone.periodicis a sequence ofPeriodicspecs (or a readyPeriodicPairs), and is the only thing that fills the boundary record’sbc(1)/bc(2)fields – the partner element and face a'P 'row is meaningless without. It is stated separately frombcbecause it is not a code but a correspondence, and the two must agree: every name coded'P 'is named by a spec and vice versa, or this raises:bc={"wall": "W ", "inlet": "P ", "outlet": "P "}, periodic=[hexmesh.Periodic("inlet", "outlet", affine.translation([0, 0, LENGTH]))]
fluidnames the region(s) that are the velocity mesh – anything else (a different region, or untagged) is conduction-only. Nek’s header calls these countsnelgv(velocity) andnelgt(total); a conjugate run needsnelgv < nelgtand the velocity elements listed first, contiguously, which is a statement about order, not just a count – sofluid=reorders the written bytes rather than takingnelv=on trust. The mesh object this returns is unchanged; only the file’s element numbering (and every row that names an element) is permuted.fluid=None– the default – writes every element as velocity-mesh (nelgv == nelgt), which is today’s behaviour and the right one for a single-domain mesh.Whenever
fluid=carves out an actual solid region (nelgv < nelgt), Nek’s.re2always carries one boundary block per solved field –read_re2_datareads at least two the momentnelgt > nelgv, regardless of what the header declares, so a file with only one is truncated from the reader’s point of view andierr``s reading the (missing) second block. ``bc.temperatureis that second field’s own name -> code table, same shape asbc.velocity, and is required exactly whenfluid=makes the two counts differ. It may also be given on a mesh that is all fluid, where temperature is transported in the flow: the file then carries both blocks, each over every element. It covers every element, not just the fluid ones – a name omitted from it is left conformal ('E ', ordinary continuity), which is normally right for a genuinely conjugate interface: velocity needs an explicit wall there because the solid side carries no velocity unknowns to continue into, but temperature is solved on both sides, so nothing needs stating:writer.to_re2(mesh, "wire_coil.re2", periodic=PERIODIC, fluid="fluid", bc=BoundaryConditions(velocity=VEL_BC, temperature=TEMP_BC))
- Parameters:
mesh (HexMesh)
filename (str)
bc (BoundaryConditions | Mapping[str, str | int | tuple[str | None, int | None] | Mapping[str, str | int | tuple[str | None, int | None] | None]] | None)
periodic (Sequence[Periodic] | PeriodicPairs | None)
fluid (str | Sequence[str] | NDArray[str_] | NDArray[bool] | NDArray[int64] | Sequence[int] | None)
- Return type:
- nekmeshpy.io.writer.quad_to_re2(mesh, filename, *, bc, fluid=None)[source]¶
Write the binary 2-D Nek
.re2of aQuadMesh–to_re2()one rung down, with the samebc=/fluid=contract:bcis required, aBoundaryConditionscarries a velocity and atemperaturetable,fluidnames the velocity-mesh region and is written first, and a mesh with a solid region (nelgv < nelgt) needsbc.temperaturefor its second boundary block.The mesh is written linear (4 corners a quad,
x[4] y[4]) at any order, and must lie in az = constplane: a 2-D.re2carries noz. A side name is an edge name, and Nek’s face1..4is the quad’s own local edge order, so a row is(quad, edge)with no remapping.There is no
periodic=here: a periodic pairing is hex-only (to_re2()), so a name coded'P 'is refused rather than written with partner element 0.- Parameters:
- Return type:
- nekmeshpy.io.writer.to_fld(mesh, filename, *, time=0.0, istep=0, wdsz=8, fluid=None)[source]¶
Write the binary Nek5000 field file (
<prefix>0.f00001) tofilename(the full name – nothing is appended).fluidmust name the same region as the matchingto_re2()call’s ownfluid=, and for the same reason: Nek reads a restart/IC field file element by element against the.re2it already loaded, so the two files’ element numbering has to agree.to_re2’sfluid=reorders its written bytes fluid-first whenever it carves out a solid region (nelgv < nelgt); ato_fldwritten in the mesh’s own, unpermuted order would then describe element i of one file and element i of the other as two different pieces of geometry – not merely stale, but silently misassigned, since both files are the same length and neither one knows it disagrees with the other.fluid=Nonewrites every element unpermuted, which agrees with an unpermutedto_re2(fluid=Nonethere too).
- nekmeshpy.io.writer.element_tag_ids(tags, n_elements)[source]¶
(per-element id (n_elements,), name per id)for a region table: 1-based positions in the sorted tag vocabulary,0where an element carries no tag.A
.vtucannot hold the names themselves – VTK’s string arrays are per-file field data, not something a cell scalar can point into – so the array written is integer, exactly asbc_idalready is. What keeps it readable is that the mapping is a function of the mesh alone:sorted(mesh.element_tags.unique())reproduces it anywhere, with no legend to carry alongside the file.
- nekmeshpy.io.writer.to_vtu(mesh, fname, *, bc=None, binary=True, point_data=None, cell_data=None)[source]¶
Write an XML VTK unstructured grid (
.vtu) of aHexMeshwith per-pointbc_idtags, and per-cellelement_tagregion ids where the mesh carrieselement_tags(seeelement_tag_ids()for the mapping).binary=Falsewrites the arrays as text instead, which is readable and diffable but costs a Python format per row.cell_datamaps a name to a(E,)or(E, k)array andpoint_datato a(P,)or(P, k)array over the mesh’s points (diagnostics: quality, displacement), each point value repeated on its corner copies;point_datais order 1 only.- Parameters:
- Return type:
- nekmeshpy.io.writer.line_to_vtu(mesh, fname, *, binary=True)[source]¶
Write an XML VTK unstructured grid (
.vtu) of aLineMesh, un-welded (one node block per line element), with per-cellelement_tagregion ids where the mesh carrieselement_tags.
- nekmeshpy.io.writer.quad_to_vtu(mesh, fname, *, binary=True, point_data=None, cell_data=None)[source]¶
Write an XML VTK unstructured grid (
.vtu) of aQuadMesh, un-welded (one node block per quad), with per-cellelement_tagregion ids where the mesh carrieselement_tags.cell_datamaps a name to a(Q,)or(Q, k)array andpoint_datato a(P,)or(P, k)array over the mesh’s points (diagnostics: quality, constraint kind, displacement); a point value is repeated on each corner copy of its vertex.point_datais order 1 only – a high-order mesh has more nodes than points.
- nekmeshpy.io.writer.boundary_to_vtp(mesh, fname, *, tag=None, binary=True)[source]¶
Write
mesh’s named faces as a lightweight VTK PolyData (.vtp) and a per-polybc_id.With no
tag, every facemesh.face_tagsnames is exported (viaquadmesh.selectonmesh.quad_mesh) – nothexmesh.boundary_mesh’s topological boundary, which drops interior planes on purpose (a T-junction’s flux plane, say) even though they carry a name. A mesh with no named faces at all falls back to the topological boundary, untagged, so an unlabelled block still exports something. Passing an explicittagstill selects one named group by way ofboundary_mesh(unchanged).Always written corners only, regardless of
mesh’s order –.vtp’s<Polys>has no curved-cell type (a VTK PolyData polygon is always flat), and a viewer only needs the outline, not curved-node fidelity. Interior volume nodes are dropped either way – a viewer only shows the surface.When the surface carries names, a sidecar
<fname minus .vtp>.groups.json({bc_id: name}) is written alongside it –.vtp’s own field-data support is a poor fit for strings, and a viewer needs the names to label a per-group visibility toggle (e.g. hiding a far-field box to see the body it encloses).
io.reader¶
Readers for Nek5000’s mesh formats: the ASCII .rea and the binary .re2, each
at the hex rung (3-D) and the quad rung (2-D) – read_rea / quad_read_rea,
read_re2 / quad_read_re2, the readers’ side of writer.to_re2 /
writer.quad_to_re2.
Only the geometry, the element regions and the boundary conditions are read – the
surrounding parameters, thermal, restart, and drive-force sections either don’t bear on
a mesh’s shape or (curved sides) aren’t supported yet and are refused rather than
silently dropped. A mesh with nelv < nel is a conjugate one: its first nelv
elements are the "fluid" region and the rest "solid". A boundary row’s raw Nek
code is its tag name, and where a file carries a second (thermal) block a side the
velocity block does not name takes the thermal block’s code; a periodic row is read as
the name "P" with its partner dropped. The row layout below (element/face packed into one field once
NELGT reaches four digits, corners grouped X,Y,Z per half rather than per axis)
follows Nek5000’s own core/reader_rea.f (rdmesh/rdbdry) exactly – verified
against its upstream source, not reverse-engineered from one file.
- exception nekmeshpy.io.reader.ReaFormatError[source]¶
Bases:
ValueErrorThe
.reafile doesn’t match the section this reader expected next.
- nekmeshpy.io.reader.quad_read_re2(path)[source]¶
Read a binary 2-D Nek
.re2into a linearQuadMesh–read_re2()one rung down, and the reader’s side ofwriter.quad_to_re2.
- nekmeshpy.io.reader.quad_read_rea(path)[source]¶
Read a 2-D Nek5000
.reamesh into a linear (order-1)QuadMeshin thez = 0plane –read_rea()one rung down, welded through the file’s own"E"rows the same way, with named rows carried over as edge tags (quadmesh.tag_edges). RaisesReaFormatErrorfor a 3-D run or a nonzero curved-side count.
- nekmeshpy.io.reader.read_re2(path)[source]¶
Read a binary 3-D Nek
.re2into a linearHexMesh– the reader’s side ofwriter.to_re2.A
.re2stores each element’s corners independently and, unlike a.rea, carries no element-to-element rows, so coincident corners are welded by coordinate at1e-7of the model size (exact doubles, so this is a rounding radius, not a tolerance to tune). Names, regions and the second block follow the module rules.
- nekmeshpy.io.reader.read_rea(path)[source]¶
Read a 3-D Nek5000
.reamesh into a linear (order-1)HexMesh.The ASCII format stores each element’s 8 corners independently – there is no shared point numbering to read directly, and floating-point round-trip through 7-significant-digit text makes a coincidence-tolerance weld genuinely fragile (on the reference file this reader was built against, no single tolerance across four orders of magnitude was both watertight and conformal). Instead this reader uses the file’s own
"E"(element-to-element) boundary rows – which name the exact connected element and face, not a inferred one – and matches each connected face pair’s 4 corners by nearest distance within that pair alone, which needs no tolerance because the search space is 4 points against 4, not the whole mesh.Named rows (
"W","v","O", …) are carried over as face tags viahexmesh.tag_faces, keyed by the raw Nek code – this reader does not rename them.nelv < nelmakes the firstnelvhexes"fluid"and the rest"solid".Raises
ReaFormatErrorfor anything outside that scope: a 2-D mesh (seequad_read_rea()), or a nonzero curved-side count (this reader reconstructs straight-sided hexes only, and silently dropping curvature would hand back the wrong geometry rather than an approximate one).