Field Dump HDF5 File Format
All field dump boxes with file_type=1 (HDF5) write a common file layout
regardless of the dump type. This page documents that layout so that custom
post-processing code can read the files directly, without going through the
Octave or Python helper functions.
See also
Field Dump — how to set up dump boxes and choose
dump_type, dump_mode, and file_type
Specific Absorption Rate (SAR) — the raw SAR dump (dump_type=29) extends this
format with extra groups (/CellData, /CellWidth)
Near-Field to Far-Field Transformation (NF2FF) — the NF2FF surface dumps (dump_type=0/1,
file_type=1) follow exactly this format
Root attributes
openEMS_HDF5_versionFormat version number (float). Currently
0.3. Absent in very old files (treated as version 0).dump_typeInteger dump type as configured in the simulation (e.g.
0for E-field TD,10for E-field FD,20for local SAR).legacy_fmtBoolean, present only in files with version > 0.2.
Trueif the file was written with--legacyHDF5Dumps; the axis order of all field datasets is then reversed (see Axis order and legacy format below).
Mesh group /Mesh
The mesh group stores the coordinates at which field values are evaluated.
What exactly those coordinates represent depends on the interpolation mode
(dump_mode) chosen when setting up the dump box:
Node interpolation (
dump_mode=1, default): coordinates are the primal mesh node lines. All field components are interpolated to the same node positions, so the mesh describes the sample locations exactly.Cell interpolation (
dump_mode=2): coordinates are dual mesh midpoints, i.e. cell-centre positions. All components are interpolated to the same cell centres.No interpolation (
dump_mode=0): coordinates are the primal mesh node lines, but the field components are not co-located — each component sits at its native Yee-grid position (staggered half-cell offsets relative to the node). The mesh lines give the grid positions; the actual sample point of each component follows the Yee staggering convention.
The dual_mesh root attribute (boolean) records which mesh was used
(False for primal/node, True for dual/cell).
Dataset |
Unit |
Contents |
|---|---|---|
|
metres |
x-coordinates (Cartesian) or ρ-coordinates (cylindrical) |
|
metres |
y-coordinates (Cartesian) or α-coordinates in radians (cylindrical) |
|
metres |
z-coordinates (both mesh types) |
For cylindrical meshes the dataset names are rho, alpha, z.
For the spherical NF2FF output mesh they are r, theta, phi.
Coordinates are stored in SI metres (the simulation length unit is
applied as a scaling factor, stored in the mesh_scaling attribute on
the /Mesh group). Angles are stored as-is (no scaling applied).
/Mesh group attributes:
mesh_type0= Cartesian,1= cylindrical,2= spherical (NF2FF only).mesh_scalingThe simulation length unit in metres (e.g.
1e-3for a mm mesh). Mesh coordinates are already multiplied by this factor; it is stored for reference.
Field data group /FieldData
All recorded field samples live under /FieldData, split into two
sub-groups depending on the recording domain.
Time-domain data /FieldData/TD
One dataset per recorded timestep, named with a zero-padded integer matching
the simulation step counter (e.g. 000100, 000200, …).
Each dataset is a 4-D array of shape:
New format (
openEMS_HDF5_version > 0.2,legacy_fmtabsent orFalse):(3, Nx, Ny, Nz)— component-major, x-inner.Legacy format:
(3, Nz, Ny, Nx)— component-major, z-inner.
The first dimension is the vector component: index 0 = x (or ρ), 1 = y (or α), 2 = z.
Each dataset carries a scalar time attribute (float, seconds) giving the
simulation time at which the snapshot was taken.
Frequency-domain data /FieldData/FD
Written when the dump has a frequency list attached (dump_type 10–15,
and SAR on-the-fly types 20–22). The group carries:
Attribute
frequency: 1-D array of all recorded frequencies in Hz.
One dataset per frequency index n (0-based), named f{n}. The dataset
format differs between the two file versions:
New format (legacy_fmt absent or False)
A single dataset f{n} with an HDF5 compound datatype {r: float32,
i: float32}, shape (3, Nx, Ny, Nz). The member names r and i
are the ones h5py looks for by default (h5py.get_config().complex_names),
so h5py reads the dataset straight into a numpy.complex64 array — no
manual conversion is needed. The dataset carries a scalar frequency
attribute (Hz).
Legacy format (legacy_fmt = True)
Two separate float32 datasets: f{n}_real and f{n}_imag, each of
shape (3, Nz, Ny, Nx). Each carries a scalar frequency attribute
(Hz).
For real-valued FD quantities (e.g. local SAR written on-the-fly by
dump_type 20–22) there is no complex pair — a single dataset f{n}
holds the scalar field, shape (Nx, Ny, Nz) (new) or (Nz, Ny, Nx)
(legacy).
Axis order and legacy format
Every dataset carries a d_order string attribute that records the axis
ordering as written to disk:
"NXYZ"— component index N is outermost, x is innermost (new default). Reading with h5py gives shape(3, Nx, Ny, Nz)with natural index order[component, ix, iy, iz]."NZYX"— z is outermost (legacy). Reading with h5py gives shape(3, Nz, Ny, Nx); transpose or swap axes before use.Scalar fields use
"XYZ"or"ZYX"respectively (no N dimension).
Version detection rule (mirrors the C++ reader):
openEMS_HDF5_versionabsent or0: always legacy.openEMS_HDF5_version> 0 and ≤ 0.2: always legacy.openEMS_HDF5_version> 0.2: read thelegacy_fmtboolean attribute; if absent, assume new format.
The d_order attribute is the authoritative source — if present, always
prefer it over version inference.
Reading field dumps
Python
openEMS.utilities.HDF5Dump reads any of the dump variants described
above — complex or real, vector or scalar, current or legacy axis order — and
always returns the data in the natural, x-inner order. Opening the file only
reads the metadata, so the dump can be inspected before any field data is
read:
from openEMS.utilities import HDF5Dump
with HDF5Dump('Ef.h5') as dump:
print(dump) # dump type, domain, grid size, region
dump.DumpType, dump.DumpTypeName
dump.IsTD, dump.IsFD # which domain(s) the file holds
dump.Shape # (Nx, Ny, Nz)
dump.Frequencies # recorded frequencies in Hz
dump.Times # recorded timesteps in s
E = dump.GetFieldAtFrequency(2.4e9)
# complex ndarray (3, Nx, Ny, Nz), first index = x/y/z component
mesh = dump.GetMesh()
x = mesh['lines'][0] / mesh['scaling'] # x-lines in drawing units
The frequency requested from GetFieldAtFrequency() must match one stored
in the file. If the file holds time-domain data instead, the frequency is
computed by an on-the-fly DFT, so the same post-processing code works whether
the dump was recorded as TD or FD. The DFT reads every timestep but holds only
one of them in memory at a time.
A region of interest can be configured on the object and then applies to every subsequent read. The selection is passed down to HDF5, so only the requested data is read from disk — reading a single plane out of a large 3D dump is much faster than reading all of it:
with HDF5Dump('Et.h5') as dump:
dump.SetPlane('z', pos=10e-3) # nearest z-line to 10 mm
dump.SetRange('x', start=-5e-3, stop=5e-3)
dump.SetSampling(2, 2, 1) # every other x- and y-line
for time, field in dump.IterTD(component='z'):
... # Ez in the selected plane
mesh = dump.GetMesh(region=True) # mesh lines matching the data
dump.ResetRegion() # back to the full dump
SetLine reduces the read to a single line, collapsing the two
perpendicular directions:
dump.SetLine('x', idx=(None, 3, 5)) # along x at y-index 3, z-index 5
dump.SetLine('z', pos=(0.0, 1e-3, None)) # along z at x = 0, y = 1 mm
The entry for each direction is given by its position in the sequence, so
there is no ambiguity about the order — the entry for the line direction
itself must be None.
There is only ever one plane, and only ever one line: calling SetPlane or
SetLine again — for the same direction or a different one — replaces the
previous collapse, so stepping through slices or switching the slice
orientation needs no reset. Ranges and sampling on the directions that stay
open are kept. SetRange is per-direction and composes across directions as
expected.
SetLine always collapses its two perpendicular directions, replacing
whatever was set for them. For the line direction itself, a setting that would
leave fewer than two lines — a former plane normal, or a previous line — is
reset to the full extent, while an existing range of two or more lines is kept.
Setting a plane and a range on the same direction contradicts itself
and raises; clear that direction first with ResetRegion(ny), which resets a
single direction and leaves the others untouched.
Directions are given as 0/1/2 or by coordinate name ('x',
'y', 'z', or 'rho', 'alpha', 'z' for a cylindrical mesh).
Positions passed as pos/start/stop are in SI units and are snapped
to the nearest mesh line; idx/idx_start/idx_stop take mesh line
indices instead. NearestIndex() converts a coordinate to an index.
The File property exposes the underlying open h5py.File for anything
not wrapped by the class, such as the /CellData and /CellWidth groups
of a raw SAR dump.
openEMS.sar_utils.readSAR() is a small convenience wrapper around the
class for the common case of reading a complete SAR result in one call.
Reading the file directly with h5py is of course possible, but then the
version, legacy_fmt and d_order handling described above has to be
repeated in your own code.
Octave / Matlab
[field, mesh] = ReadHDF5Dump('Et.h5');
% field.FD.values{1} — complex array (Nx, Ny, Nz, 3) after transposing
% mesh.lines{1/2/3} — coordinate vectors in metres
% mesh.type — 0 Cartesian, 1 cylindrical
ReadHDF5Dump handles legacy/new detection and axis transposition
automatically. Use it in preference to reading the HDF5 file directly.