Model Output
Field(s) output
gprMax produces an output file that primarily contains time history data for electromagnetic field outputs (receivers) in the model. By default, a single run uses the input file’s basename with the .h5 extension: model.in produces model.h5. The output uses the widely-supported HDF5 format which was designed to store and organize large amounts of numerical data. There are a number of free tools available to read HDF5 files. MATLAB also has high- and low-level functions for reading HDF5 files, including h5info, h5disp, and h5read. The Utilities toolbox supplies gprmax_read_h5.m to load the complete hierarchy into a MATLAB structure and gprmax_h5_to_mat.m to create MATLAB v7.3 MAT files. These functions reconstruct complex arrays and retain gprMax’s documented multidimensional array ordering. Its modernised plot_Ascan.m and plot_Bscan.m functions use the stored physical timing and support receiver fields, subgrids, and merged terminal-voltage scans. gprMax also includes Python modules in the Plotting toolbox to view output data.
Warning
Geometry files and simulation results both use .h5. For a single
run, model.in produces model.h5 by default. If the geometry
input is that same file, saving the simulation results overwrites it
without confirmation. Importing the geometry does not protect the
original file from later output writes.
Use distinct paths for geometry and results: for example, name the
geometry file model_geometry.h5, choose a separate output directory,
or set a different result basename with -o on the command line or
outputfile in the Python API. The same precaution applies when
choosing a geometry-export filename.
File structure
The output file has the following HDF5 attributes at the root (/):
gprMaxis the version number of gprMax used to create the outputTitleis the title of the modelIterationsis the number of iterations for the time window of the modelnx_ny_nzis a tuple containing the number of cells in each direction of the modeldx_dy_dzis a tuple containing the spatial discretisation, i.e. \(\Delta x\), \(\Delta y\), \(\Delta z\)dtis the time step of the model, i.e. \(\Delta t\)srcstepsis the spatial increment used to move all sources between model runs.rxstepsis the spatial increment used to move all receivers between model runs.nsrcis the total number of sources in the model.nrxis the total number of receievers in the model.nportscounts voltage-source and explicitly requested rational-network port outputs inports; it does not includetls,frillsoreigenmode_ports.neigenmodeportsis the number of eigenmode source/receiver port monitors.SourceExcitationSchemaVersionidentifies the schema used for exact source histories stored below local source groups.ReceiverTimingSchemaVersionidentifies the schema used for receiver dataset time offsets.ReceiverOrderSchemaVersion=1identifies the public receiver ordering contract.ReceiverOrder=constructionmeans rank-independent construction order;ReceiverLayoutidentifies the ordered receiver declarations.
The output file contains HDF5 groups for sources (srcs), transmission lines
(tls), magnetic frill sources (frills), receivers (rxs),
voltage-source and rational-network ports (ports), SAR outputs (sar), radiometric
absorption outputs (radiometry), and KSIR outputs (ntff) when
requested. Eigenmode sources and receivers add eigenmode_ports. Within these are
further groups for each named or numbered output.
Absorbed power density and specific absorption rate
A requested main-grid SAR output adds /sar/<id>; an output attached to a
subgrid adds /subgrids/<subgrid ID>/sar/<id>. gprMax transforms only the unique
Yee electric edges required by the selected tagged cells and only at the
requested frequencies; it does not store a full time history for every cell.
The serial CPU solver uses a Cython/OpenMP sparse transform. CUDA, OpenCL, and
Metal accumulate the same sparse transforms in device memory and download only
the completed complex edge spectra. Local SAR and any requested spatial mass
averages are then evaluated on the host using the common implementation.
With MPI domain decomposition, every rank transforms only the sparse electric
edges needed near its selected tagged cells. After time stepping, uniquely
owned edge spectra and owned-cell metadata are gathered once. The coordinator
then collocates the global Yee-edge spectra, applies source or port
normalisation, and performs any mass averaging on the complete tag volume.
This avoids additional collectives inside the timestep loop and permits both
tag regions and averaging cubes to cross rank boundaries. It also avoids
depending on diagonal MPI halo values, which the field solver does not require
and therefore does not exchange.
The transform uses the engineering convention
The three-dimensional Yee geometry is retained in both 3-D and reduced 2-D models. In 3-D, the four parallel Yee edges of each electric component are averaged as complex phasors to the cell centre. A 2-D TM model uses only the electric component parallel to the invariant axis, at invariant index zero; its four edges surround the cell in the transverse cross-section. A 2-D TE model uses the two electric components tangential to the invariant axis on the live central plane at invariant index one. Each TE component is averaged from its two genuine tangential edges. The second TE cell exists only to preserve the 3-D Yee staggering and is not a second physical SAR plane. Thus, for example,
The corresponding coordinate permutations apply to invariant x and y models. All inactive components remain zero. Two-dimensional TE/TM FDTD SAR is useful for rapid invariant-model dosimetry and polarisation studies [LWI2019]. With peak (not RMS) phasors, the local time-average absorbed power density and SAR are [IEEE62704-3]
Thus absorbed_power_density is in W/m3, density is in
kg/m3, and sar is in W/kg. This evaluates dielectric/conductive
loss directly and does not explicitly form a current-density array. The cell
material supplies \(\sigma_{\mathrm{eff}}\) and \(\rho\); dielectric
smoothing of Yee-edge update coefficients does not average mass density or
tag membership.
For an isotropic material, all three loss spectra are identical and the expression reduces to \(\sigma_{\mathrm{eff}}|\mathbf E|^2/2\). Grid-aligned diagonal anisotropy uses the ordered x/y/z materials supplied to the volume primitive, including each direction’s dispersive poles. An arithmetic mean of directional conductivities is not used: it would generally give the wrong absorption for a polarised field. A zero field component contributes zero without renormalising the sum; zero static conductivity does not suppress loss from dispersive poles. General off-diagonal tensors are not supported. This is electric absorption only, not magnetic material heating.
Warning
SAR and radiometry do not include magnetic absorption. A runtime warning identifies magnetic materials (relative permeability different from one or nonzero magnetic conductivity) in the selected cells outside PML, including directional material constituents. Magnetic properties still affect the FDTD fields; they are not ignored by the solver. When magnetic conductivity is nonzero, the reported absorption and SAR are not total absorption or total SAR, and radiometric weights omit that magnetic loss. Lossless permeability alone adds no magnetic heating. Ideal PMC constraints are not treated as finite-conductivity absorbers for this warning.
For SAR, the three directional material definitions must all specify the same positive mass density. Missing or conflicting densities stop the calculation; they are not averaged. Radiometry has no density requirement. Spatial interpolation of each complex electric component from its Yee edges to the cell centre remains separate from this directional loss calculation.
Because a finite transient spectrum is not itself a continuous-wave
excitation, waveform normalisation divides the field DFT by the DFT of the
selected source waveform and multiplies it by TargetAmplitude. Exactly
one active source may use that waveform. For a Hertzian electric dipole,
current_moment divides by the product of waveform spectrum and source-edge
length, so TargetAmplitude is \(I\ell\) in A m. For a discrete plane
wave, the source waveform is the incident electric-field magnitude in V/m.
It can either be used directly or converted to an incident power flux using
The incident_flux mode scales to TargetFlux in W/m2; the
complex permittivity and permeability of the plane wave’s source-side
material are used at every requested frequency. Alternatively, incident- or
accepted-power normalisation multiplies the field DFT by
The requested port power is obtained through the same terminal/modal power
adapter used for antenna gain. Non-positive, non-finite, or invalid port
powers produce invalid SAR bins rather than unbounded scaling. Frequencies
below SourceFloorDB are likewise marked invalid and stored as NaN.
Transforms of stored source histories evaluate their phase arguments in at
least double precision, even for single-precision simulations. This reduces
phase-rounding errors at spectral notches; it does not make normalisation by
an arbitrarily weak source spectrum reliable. The source-support cutoff and
validity masks still apply, and the transform output retains the configured
complex precision.
Source and port normalisation are resolved across the complete model rather
than only the grid containing the SAR output. Consequently, a source on the
main grid can illuminate and normalise tagged tissue sampled at every fine
timestep inside a subgrid. A subgrid port uses the model-wide qualified
reference <subgrid ID>/<port ID>.
The datasets include frequency, cell_indices, tag_id,
material_id, density, source_spectrum, source_relative_db,
source_valid, incident_power, incident_flux, mesh_valid,
valid, cells_per_wavelength,
limiting_material, absorbed_power_density, and sar. Each
tags/<name> subgroup contains cell count, integrated mass and absorbed
power, mass-average SAR, and peak voxel SAR.
CellIndexOrigin and CellCentreOffset map the integer
cell_indices to physical cell-centre positions. CellIndexFrame is
main-grid for a normal output and subgrid-local for an HSG output.
MPI output uses globally sorted main-grid cell indices and the same HDF5 schema
as the serial solver. The gathered sparse spectra and completed frequency-by-
cell arrays reside on the coordinator during finalisation; for extremely large
tag volumes this coordinator memory is the present scalability limit.
MPI material_id values refer to the output-local materials/id and
materials/name catalogue. Generated directional materials can have
different numeric IDs on different ranks; their definitions are gathered once
after time stepping, without changing the reusable grid’s material IDs.
In a 2-D model, local absorbed_power_density and sar retain their
ordinary W/m3 and W/kg units. Integrated quantities describe the
invariant geometry per unit length:
Consequently, a 2-D tag subgroup contains MassPerLength in kg/m and
absorbed_power_per_length in W/m. Its mass_average_sar remains in
W/kg. Dimensionality, ModelMode, Polarisation, InvariantAxis,
LiveInvariantIndex, and ActiveElectricComponents make the convention
explicit. Port powers used for 2-D normalisation are likewise interpreted in
W/m rather than W.
The TMz and TEz cell collocation, local SAR, and absorbed power per unit length are compared with exact lossy-cylinder series in Two-dimensional SAR in lossy dielectric cylinders.
Spatial averaging is not performed by default. This keeps the application-
neutral local quantities available without imposing a bioelectromagnetic
1 g/10 g convention or its potentially substantial post-processing cost.
When one or more target masses are explicitly requested, the output also
writes spatial_average/<mass>g. The standard 1 g and 10 g outputs are
requested with averaging_masses=(0.001, 0.01). They use the two-step
cubical mass-averaging procedure of IEC/IEEE 62704-1 [IEEE62704-1]: first a
cube is expanded symmetrically about each tissue voxel; remaining boundary
voxels are then evaluated with six face-centred cubes. During centred-cube
growth every complete voxel shell is checked to ensure that each of its six
faces touches or intersects tissue. A cell is marked as covered when more
than 99.9% of its volume lies in a valid centred cube. Fractional
boundary-voxel volumes are used to reach the target mass. Density is
piecewise constant within each tagged FDTD cell: a fractional contribution
has mass
where \(0\leq q_i\leq1\) is only the geometrical fraction inside the
averaging cube. Density is not interpolated or Yee-edge averaged. The selected
tags collectively define tissue; cells outside them are background. Each mass
group contains sar, status, averaging_mass,
averaging_volume, orientation, peak_sar, and peak_cell.
Status values are 0 invalid/background, 1 unused boundary, 2 covered by a
valid centred cube, and 3 a valid centred-cube location. Orientation 7 is a
centred cube and 1–6 identify the face-centred directions.
The density-, tag-, and grid-dependent averaging-cube geometry is constructed once for each requested mass and reused for every frequency. The compiled OpenMP implementation therefore avoids repeating the expensive target-mass search for a frequency sweep.
Spatial 1 g/10 g averaging is currently restricted to 3-D models. A reduced
2-D field solution is invariant, so such an average would require a deliberate
virtual extrusion of the density, tags, and fields along the invariant axis;
the one-cell TM and two-cell TE storage thicknesses must not be treated as a
finite anatomical volume. Until that invariant-extrusion procedure is added
and separately validated, a 2-D SAR request must leave
averaging_masses=().
Cells inside either a domain-boundary PML or an internal PML slab are always
excluded, even when their geometry tag is selected. PML attenuation is a
numerical coordinate stretching and must not be counted as physical material
absorption, tissue mass, or SAR. The group attributes PMLCellPolicy and
ExcludedPMLCellCount record this operation.
The requested frequencies must be below temporal Nyquist. By default they
must also have at least ten cells per shortest wavelength in every model
material; a lambda/8 criterion may be selected. In a 2-D TM or TE model this
check uses only the two propagation directions, excluding the invariant-axis
thickness. In 3-D it uses all three spatial steps. The same rule applies to
port-output wavelength validation. The nyquist research mode
retains frequencies outside that spatial criterion and records the mesh
validity metadata, but does not make those results physically reliable.
For lossy or dispersive media this output guard uses \(c/(f|\sqrt{\varepsilon_r^*\mu_r^*}|)\) as a conservative spatial scale, including both electric and magnetic loss. It is not the physical phase wavelength. The separate pre-simulation spatial-resolution diagnostic reports phase wavelength and attenuation length separately.
Radiometric absorption weighting
A Radiometry request writes /radiometry/<id> on the main grid, or
/subgrids/<subgrid ID>/radiometry/<id> on a subgrid. It uses the same
sparse electric-field transforms, cell-centre collocation,
\(\sigma_{\mathrm{eff}}\), source/port normalisation, PML exclusion, and
mesh-validity checks as SAR. It deliberately does not use mass density and
does not calculate SAR or a 1 g/10 g average. This makes it suitable for
lossy geological and planetary materials for which density is unavailable or
irrelevant to the electromagnetic absorption calculation.
The electric-only absorption limitation and its runtime warning apply to all radiometry outputs and normalisations.
The principal local quantities are absorbed_power_density and
normalised_absorption_density. The latter has a definition appropriate to
the selected excitation:
This is the active-mode reciprocity construction used for microwave radiometry. At one frequency the cell weight for an incident-power reference is
and Wu and Nieh’s finite-band weighting factor is
The normalised_absorption values are the per-frequency integrand; a
receiver-specific quadrature over frequency remains post-processing because
its bandshape is not an FDTD property. The equivalent continuous weighting
function commonly used in radiometric forward models is
which integrates to unity over the chosen receiving volume [WU1995] and
[ROD2013]. It can be formed from
normalised_absorption_density without rerunning the model. Normalising to
accepted rather than incident power removes mismatch loss from the spatial
weight but does not otherwise change its shape.
For a 3-D power-normalised port, \(w\) has units m-3 and its volume integral is the fraction of the reference power absorbed in a tag. For plane-wave flux, it has units m-1 and its volume integral is an absorption cross section in m2. A 2-D invariant model instead integrates over area and reports, respectively, a dimensionless absorbed fraction or an absorption cross section per unit invariant length in metres. For a portless source the integral is absorbed power per squared native source amplitude; examples include V/m for a plane-wave waveform, A m for Hertzian current moment, and V for a voltage source.
Each tags/<name> subgroup stores the integrated physical absorbed power
and normalised_absorption. These tag-resolved weighting quantities are the
electromagnetic part needed by radiometer forward models. gprMax does not yet
combine them with physical temperature, receiver bandwidth, receiver noise,
or a radiative-transfer model to produce brightness or antenna temperature;
those are separate measurement-model inputs rather than FDTD field
quantities.
Study outputs
Reusable parameter studies add a root study group. Its attributes are
Type, CaseID, CaseIndex (one based), CaseCount,
GeometryReused, and, for CSV studies, SourcePath. The source
dataset preserves the complete CSV text. definition stores the normalised
full study as JSON, while resolved_case contains the post-validation values
actually applied to every study-managed object, including baseline receivers
and implicitly disabled sources.
Study-managed source and receiver groups also carry a StudyID attribute,
including the tls and frills groups used by a source study. This
provides an unambiguous link back to the case table.
For a plane-wave study, resolved_case records the requested case together
with the actual rationalised propagation angles and integer DPW mapping. Each
case remains an ordinary numbered model output; no aggregate matrix is needed
because RCS patterns from different illuminations are independent results.
For a source study, resolved_case records every stateful terminal,
including sources omitted from the sparse case table. active=false and
scale=0 identify a passive physical termination rather than an object
removed from the model. Transmission-line, magnetic-frill, rational-network,
receiver, port, and declarative NTFF datasets in each numbered file contain
only that case’s reset state.
Every case in a finite-resistance voltage-port study additionally contains
study/port_response. DrivenSourceID and DrivenPortID identify its
input port; S_source_column contains the power-normalised raw source-plane
response for every output port. gap_correction_c stores the dimensionless
parallel-gap admittance \(Z_{0,p}Y_{\mathrm{gap},p}\) used by the matrix
correction.
After all requested cases finish, gprMax writes <output>_study.h5. Its
principal datasets are:
frequency: common frequency axis;port_idsandsource_ids: output-port and deterministic source order;case_ids: case contributing each input-port column;reference_impedance: positive real wave-reference impedance per port;gap_correction_c: numerical gap shunt correction for every frequency and port;S_source: uncorrected source-plane S matrix;S: matrix after removing all numerical gap admittances;valid_S_sourceandvalid_S: element validity masks.
Both matrices use axis order
S[frequency, output_port, input_port]. The Complete attribute states
whether every input-port column is present. A restarted study loads compatible
columns from an existing aggregate file and replaces the newly evaluated
columns; an incompatible existing file is rejected rather than mixed with new
results.
Every eigenmode-study case instead contains
study/eigenmode_response. InputPort and InputMode identify the
nominal incident modal channel. incident and outgoing contain the
complete measured modal vectors for that run, ordered by channel_ports
and channel_modes; power_wave_valid and coefficient_valid_wave are their
validity masks. S_column is the single-source-normalized per-run
diagnostic retained alongside those raw waves. It is not the authoritative
column when passive ports have residual incident waves.
The eigenmode aggregate <output>_study.h5 contains frequency,
channel_ports, channel_modes, case_ids, incident_matrix,
outgoing_matrix, power_wave_valid_matrix,
coefficient_valid_wave_matrix, deembedding_condition_number,
deembedding_valid, S, power_wave_valid_S, and coefficient_valid_S.
Only these descriptive validity names are supported. Its convention is
S[frequency, output_channel, input_channel]. Modal channels can represent
different mode counts on different ports; the two channel-index datasets are
therefore authoritative and should be used instead of assuming one mode per
port. The aggregate \(S\) satisfies \(B=SA\) for the stored measured
incident matrix \(A\) and outgoing matrix \(B\); it is calculated by
a conditioned solve rather than independent scalar division. A restarted
study retains the raw case columns and repeats this complete solve.
Both run matrices use
[frequency, modal_channel, excitation_case] axis order.
When an array codebook is attached, the same aggregate may also contain:
/array_codebook/
definition [canonical JSON, always present]
source [original JSON text, when loaded from disk]
/embedded_far_fields/<transform_id>/<output_id>/
frequency
theta
phi
Etheta [frequency, direction, channel]
Ephi [frequency, direction, channel]
valid [frequency, channel]
sphere/
theta
phi
weights
Etheta [frequency, sphere_direction, channel]
Ephi [frequency, sphere_direction, channel]
raw_runs/
Etheta [frequency, direction, excitation_case]
Ephi [frequency, direction, excitation_case]
valid [frequency, excitation_case]
sphere/{Etheta,Ephi}
/array_states/<state_id>/
drives/{port,mode,power_w,phase_deg,delay_s}
incident
outgoing
active_reflection
incident_power
reflected_power
accepted_power
tarc
valid
far_fields/<transform_id>/<output_id>/
Etheta
Ephi
radiation_intensity
radiated_power
directivity
directivity_dbi
gain
gain_dbi
realized_gain
realized_gain_dbi
radiation_efficiency
total_efficiency
maximum_directivity
maximum_directivity_dbi
maximum_theta
maximum_phi
valid
The embedded fields have units of range-normalized field per square root watt
of incident modal power. The requested-direction and full-sphere arrays retain
complex fields, rather than per-channel directivity or power, so coherent
cross terms are included when a state is synthesized. The sphere weights
integrate radiation intensity over solid angle. valid is false wherever
an active input does not have a physical propagating power-wave S coefficient;
such bins are stored as NaN for power-derived state results.
definition is a complete portable representation even when the codebook
was constructed with the Python API; source preserves the user’s original
text when it came from a JSON file.
/
study/ [optional]
source [CSV studies]
definition
resolved_case
port_response/ [port studies]
port_ids
source_ids
frequency
reference_impedance
gap_correction_c
S_source_column
valid_S_source_column
eigenmode_response/ [eigenmode studies]
channel_ports
channel_modes
frequency
S_column
power_wave_valid_S_column
coefficient_valid_S_column
incident
outgoing
power_wave_valid
coefficient_valid_wave
rxs/
rx1/
Name
Position
Ex
Ey
Ez
Hx
Hy
Hz
Ix [optional]
Iy [optional]
Iz [optional]
rx2/
...
srcs/
src1/
Type
Position
ID
GridPosition
Polarisation
excitation/
samples
src2/
...
tls/
tl1/
Position
Resistance
dl
Vinc
Iinc
Vtotal
Itotal
frequency
S11
Zin
Yin
S11_current
Zin_current
...
tl2/
...
frills/ [optional]
frill1/
Position
Polarisation
Z0
Mirror1Face
Mirror2Face
Mirror1
Mirror2
Vinc
Vtotal
Itot
frequency
S11
Zin
Yin
...
frill2/
...
ntff/ [optional]
<monitor name>/
...
ports/ [optional]
<port ID>/
frequency
S11
Zin
Yin
...
eigenmode_ports/ [optional]
port1/
frequency
incident
outgoing
electric_cross_power_matrix
power_matrix
anchor_mode_valid
anchor_mode_reference_valid
anchor_mode_propagating
anchor_balanced_power
reference_basis_valid
coefficient_valid
power_basis_valid
power_matrix_valid
power_wave_valid
condition_number
S
coefficient_valid_S
power_wave_valid_S
active_S
active_S_driven
coefficient_valid_active_S
power_wave_valid_active_S
Within each individual rx group are the following attributes:
Nameis the name of the receiver if specified. Otherwise ‘Rx(x,y,z)’, where x,y,z is the position of the receiver, is used.Positionis the x, y, z position (in metres) of the receiver in the model.GridPositionis the integer x, y, z position of the receiver on its owning grid.BuildIndexis the zero-based public construction ordinal within this grid. For ordinary solver output,rxNhasBuildIndex=N-1.NameKinddistinguishes a user label (user) from an automatically generated coordinate label (generated).
Receiver numbering and cross-version processing
Public receivers are numbered in construction order, independently of their names and the MPI partition. Receiver arrays follow their x/y/z traversal order (z varies fastest). Private port samplers do not consume public numbers. Each subgrid has its own numbering namespace. The solver’s runtime receiver list and accelerator buffer pages are not reordered when writing a file.
Construction order follows command build priorities: individual Rx
commands are built before RxArray commands. It is not a promise of literal
input-line order across interleaved command types. The ordinal survives MPI
migration and geometry reuse. ReceiverLayout is a SHA-256 digest of the
ordered declarations (explicit label or null, sorted requested components,
study ID). Coordinates are intentionally excluded so a declared acquisition
can move between runs. This digest describes an acquisition layout, not
a model UUID or proof that two arbitrary simulations are physically equivalent.
Do not reorder anonymous declarations between runs and assume their ordinal
identities remain the same. Prefer unique names for independently built models.
Earlier v4 development outputs sorted receiver Names lexicographically;
v3 used insertion order. Neither has the new ordering metadata. Consequently,
the same /rxs/rx1 path can refer to different receivers across versions.
Existing files are not rewritten. Low-level serial writers given receiver
objects without build ordinals report ReceiverOrder=runtime and do not
claim stable construction identities. Distributed output requires ordinals.
The current Python merge, SEG-Y/SEG-2/DT1 collection and Marimo stacking tools
anchor the selected receiver in the first file, then match its identity in
later files. Unique StudyID takes precedence, followed by unique Name;
matching construction layout/index also supports generated or duplicate names.
For generated names in the same layout, the ordinal takes precedence over
coordinates embedded in the name, which may change during a scan. Ambiguous
matches fail (Marimo skips the trace with a warning). Legacy single-receiver
files without labels remain supported; unlabeled or duplicate-labeled legacy
multi-receiver files require explicit, verified per-file selections rather
than an inferred mapping. Positions may move and are kept with their samples.
Merging retains the first file’s paths and identity metadata. Each receiver’s
trace_metadata/rxs/rxN/InputReceiverPath and Name datasets retain its
per-input mapping alongside the existing per-trace positions. Derived
ImpulseResponse files retain selected receivers’ original paths/indices;
these subsets can contain gaps, so readers should enumerate actual groups
and sort numeric suffixes rather than construct paths from 1..nrx.
Use name-based selections when migrating saved scripts:
from gprMax.toolboxes.SFCW.processing import load_receiver
trace = load_receiver("run.h5", "name:surface", "Ez")
from gprMax.toolboxes.Utilities.outputfiles_merge import get_output_data
data, dt = get_output_data("merged.h5", 1, "Ez", receiver_name="surface")
SFCW/FMCW --receiver and ImpulseResponse receiver selections also accept
name:surface or study:identifier. ImpulseResponse CLI syntax appends
the component, for example --receiver name:surface:Ez. Export utilities
and Python B-scan plotting accept --trace-group name:surface. Export
--receiver N selects N in the first input file. The shared Python
receiver_identity utility also offers per-grid build:N selection.
FMCW automatically identity-matches an omitted background/incident receiver. An explicitly supplied background/incident receiver is an intentional per-file override, allowing reference measurements at a different point. AntennaPatterns still uses its own zero-padded radius/angle Names to order bins; do not replace that consumer-side sort with public group order. Native ports and NTFF retain their separate ID-based namespaces.
MATLAB plot_Ascan and plot_Bscan accept ReceiverName (and Grid
for a subgrid). gprmax_receiver_path(file, name, grid) resolves a unique Name
for lower-level readers/converters. Numeric/path selections remain file-local.
The interactive legacy converter accepts only a single receiver; use an
explicitly selected modern reader/exporter for multi-receiver data.
Upgrade processing tools together with the solver. Old installed tools and
external scripts cannot infer this mapping from numeric paths alone. Review
stored numeric selections against Name/StudyID and positions. Regression
comparisons now match receiver identities, but strict whole-group/file HDF5
comparisons will still report the new metadata: verify the signals and then
deliberately update reference files, rather than regenerating them blindly.
Within each individual rx group can be the following datasets:
Exis an array containing the time history (for the model time window) of the values of the x component of the electric field at that receiver position.Eyis an array containing the time history (for the model time window) of the values of the y component of the electric field at that receiver position.Ezis an array containing the time history (for the model time window) of the values of the z component of the electric field at that receiver position.Hxis an array containing the time history (for the model time window) of the values of the x component of the magnetic field at that receiver position.Hyis an array containing the time history (for the model time window) of the values of the y component of the magnetic field at that receiver position.Hzis an array containing the time history (for the model time window) of the values of the z component of the magnetic field at that receiver position.Ixis an optional array containing the time history (for the model time window) of the values of the x component of current (calculated around a single cell loop) at that receiver position.Iyis an optional array containing the time history (for the model time window) of the values of the y component of current (calculated around a single cell loop) at that receiver position.Izis an optional array containing the time history (for the model time window) of the values of the z component of current (calculated around a single cell loop) at that receiver position.
Every receiver component dataset has SampleInterval, TimeSampleOffset,
and Quantity attributes. Electric fields have TimeSampleOffset=0 and
represent \(E^n\). Magnetic fields and magnetic-loop currents have
TimeSampleOffset=-\Delta t/2 and represent \(H^{n-1/2}\) at stored
sample index \(n\). These explicit physical times are important when
combining electric and magnetic quantities or deconvolving a source.
Receivers are observed before each field update. Sample zero is the initial
state: magnetic fields are zero, but an active zero-resistance voltage source
can prescribe a nonzero electric field at its edge before this observation.
Within each individual src group are the following attributes:
Typeis the type of source, e.g. Hertzian dipole, voltage source etc…Positionis the x, y, z position (in metres) of the source in the model.ID,GridPosition, andPolarisationidentify the source and its electric or magnetic Yee component.
Each supported local source also contains an excitation group. Its
samples dataset is the exact scalar history consumed by the solver, with
the update look-ahead sample removed. SampleInterval and
TimeSampleOffset define the physical time of sample \(n\) as
\(t_n=n\Delta t+t_0\); DrivingQuantity, Units, SpatialScale,
UpdateLattice, and waveform attributes describe the excitation. A
WaveformEvaluationTimeOffset attribute separately records the time used
to evaluate the waveform function for source sample \(n\). A
resistive voltage source and Hertzian electric dipole, for example, use
\(t_0=\Delta t/2\). Hard voltage sources initialise \(E^0\) and then
prescribe \(E^{n+1}\) at \((n+1)\Delta t\); their two offsets are zero.
Their history contains samples 0 through \(N-1\), including the initial
prescription, but not the terminal \(E^N\) update. Older hard-source files
have physical offset \(\Delta t\) and evaluation offset zero; readers
must honour the stored metadata rather than assuming either convention.
Transmission-line sources store
their two staggered histories as samples_whole and samples_half;
samples is a non-duplicating HDF5 link to the whole-step generator-voltage
reference.
This timing-aware source schema is used by the impulse-response waveform-synthesis toolbox, the SFCW toolbox, and the FMCW toolbox, and is also available for other file-based deconvolution and post-processing.
Within each individual tl group are the following attributes:
Positionis the x, y, z position (in metres) of the source in the model.Resistanceis the resistance of the transmission line.dlis the spatial discretisation of the transmission line.ReferenceImpedanceis the real reference impedance used for S11 and is equal toResistance.SpectrumLimitMode,MinimumWavelengthCells,MeshFrequencyLimit,NyquistFrequency, andLimitingMaterialdescribe the automatically selected frequency band.ZinPrimaryMethodidentifies the voltage-wave S11 result as the primary impedance calculation.CurrentCheckMethodidentifies the independent discrete-line current-wave calculation.
Within each individual tl group are the following datasets:
Vincis an array containing the time history (for the model time window) of the values of the incident voltage in the transmission line.Iincis an array containing the time history (for the model time window) of the values of the incident current in the transmission line.Vtotalis an array containing the time history (for the model time window) of the values of the total (field) voltage in the transmission line.Itotalis an array containing the time history (for the model time window) of the values of the total (field) current in the transmission line.frequencyis the authoritative non-negative frequency axis in Hz.Vincident_spectrum,Vreflected_spectrum, andVtotal_spectrumare the complex voltage spectra.Iincident_spectrumandItotal_spectrumare the complex current spectra after accounting for the current’s half-time-step staggering.S11is the voltage-wave reflection coefficient \((V_\mathrm{total}-V_\mathrm{inc})/V_\mathrm{inc}\).ZinandYinare the input impedance and admittance derived fromS11and the line resistance.S11_currentandZin_currentare independent checks calculated from the line current. The current is displaced from the voltage node by both half a time step and half a line cell; gprMax removes both offsets using the discrete 1D transmission-line dispersion relation. A simple phase shift of the total current alone is not sufficient because incident and reflected current waves require opposite spatial corrections.valid_S11,valid_Zin,valid_Yin,valid_S11_current, andvalid_Zin_currentare per-bin integer masks.source_valid,mesh_valid,line_propagation_valid,incident_relative_dB, andcells_per_minimum_wavelengthprovide the corresponding diagnostics.
Within each individual frill group are the following attributes:
Positionis the x, y, z position (in metres) of the feed point in the model.Polarisationis the antenna axis the source drives current along (x,y, orz).Z0is the user-supplied characteristic impedance (Zcoax), and is also the reference impedance used for S11.InnerConductorRadiusis the radius \(a\) obtained from the mandatory co-located#thin_wire.CurrentTimeApproximationisaveragefor Hyun’s recommended average of the adjacent magnetic half-step currents.FeedSelfAdmittanceis the precomputed Cartesian feed-cell coefficient \(G_f\) (Siemens) used to solve the current feedback in closed form.TimeOffsetis zero:Vinc,Vtotal, and the averagedItotare all centred at integer electric-field times.Mirror1FaceandMirror2Facename the two domain faces transverse toPolarisation(for examplex0/y0for a z-polarised source).Mirror1andMirror2record whether the feed point actually sits on a symmetry-plane corner declared with#symmetry_boundaryat that face.SpectrumLimitMode,MinimumWavelengthCells,MeshFrequencyLimit,NyquistFrequency, andLimitingMaterialdescribe the automatically selected frequency band, as fortlgroups.ZinPrimaryMethodidentifies the voltage-wave S11 result as the primary impedance calculation - there is no separate current-based cross-check here, unlike a transmission line, since the frill’s voltage and current histories are solved together at the same instant, not staggered.
Within each individual frill group are the following datasets:
Vincis an array containing the time history of the incident voltage (half the generator waveform).Vtotalis an array containing the time history of the total terminal voltage \(V_\mathrm{ab}\).Itotis an array containing the time history of the total current at the feed point, averaged from the adjacent magnetic half steps and generalised for a symmetry-mirrored feed point.frequency,S11,Zin,Yin, and their associatedvalid_S11/valid_Zin/valid_Yin/source_valid/mesh_valid/incident_relative_dB/cells_per_minimum_wavelengthdiagnostics have the same meaning as the correspondingtldatasets.
Transmission-line S11 and impedance output
S11, input impedance, and input admittance are generated automatically for every transmission-line source; no additional receiver is required. With the real line resistance \(Z_0\) as the reference impedance, the primary results are
This S11-based Zin is the primary result because direct division by the
terminal current becomes ill-conditioned at frequencies where that current
approaches zero. The independently de-embedded current result remains in
Zin_current so that the line coupling and the voltage-wave result can be
checked. Algebraically undefined open- or short-circuit quantities are stored
as complex NaNs and identified by their validity masks.
The stored spectrum uses the native resolution \(\Delta f=1/T\) and is
capped automatically at the lambda/10 mesh limit of the most restrictive
material in the model. The original Vinc, Iinc, Vtotal, and
Itotal histories remain available for users who need to reprocess a wider
research band.
For example, the valid S11 and impedance bins can be read directly:
import h5py
import numpy as np
with h5py.File('model.h5', 'r') as output:
line = output['tls/tl1']
frequency = line['frequency'][...]
s11 = line['S11'][...]
zin = line['Zin'][...]
valid = (
line['valid_S11'][...].astype(bool)
& line['valid_Zin'][...].astype(bool)
)
s11_db = 20 * np.log10(np.abs(s11[valid]))
resistance = zin.real[valid]
reactance = zin.imag[valid]
Magnetic-frill-source S11 and impedance output
S11, input impedance, and input admittance are generated automatically for
every #magnetic_frill_source, exactly as for a transmission line; no
additional receiver is required (the electric field
component along the polarisation axis is identically zero at the feed point
by construction, so no field sample is possible there in the first place).
Main-grid results are stored at /frills/frillN. A Python API frill inside
a subgrid is stored at /subgrids/<subgrid ID>/frills/frillN; its
Position is reported in global physical coordinates, while its histories,
frequency axis, and validity limits use the owning subgrid’s finer dt and
dl.
With the frill’s user-supplied characteristic impedance \(Z_0\) as the
reference impedance,
Unlike a transmission line, there is no independent current-based cross-check: \(V_\mathrm{inc}\), \(V_\mathrm{ab}\), and \(I_\mathrm{tot}\) are centred at the same integer time. The current is Hyun’s average of the preceding and following magnetic half-step values; the following value depends on the voltage applied in that update, so gprMax solves the resulting feed-cell relation analytically. There is therefore no remaining leapfrog phase shift to de-embed. \(I_\mathrm{tot}\) is formed directly from the mandatory thin wire’s stored Mäkinen-projected H edges, consistent with the \(F k_H\) source deposit. At every sample the stored histories satisfy
Set spectrum_limit directly on the magnetic-frill source when a limit
other than the default lambda/10 band is required.
Rational-network port output
The #network_port command and NetworkPort Python object write a
rational terminal beneath /ports/<terminal ID>. The external-network
current is defined positive from the FDTD gap into the network,
Here \(V_g=0\) for a passive terminal. For antenna and accepted-power calculations, the current entering the electromagnetic structure removes the numerical parallel Yee-gap admittance,
For each rational term, \(\dot{x}_m=p_mx_m+r_mu\), where \(u=V-V_g\). Its value at any fraction \(\theta\) of a time step is calculated without a finite-difference approximation to \(x_m\),
with the coefficients obtained from the exact convolution of an exponential pole with a linearly varying voltage. The implementation uses \(\theta=1/2\) directly for the locally implicit Ampere update and \(\theta=1\) to advance stored state. This is the relevant Giannakis–Giannopoulos improvement [GIA2014] to the classic PLRC lumped-network treatment of [PER1999] and [CHE2007]: the half-step pole current is obtained directly rather than by averaging adjacent integer-time values.
The reported quantities are \(S_{11}=V^-/V^+\), \(Z_\mathrm{in}=V/I_\mathrm{terminal}\), and \(Y_\mathrm{in}=I_\mathrm{terminal}/V\). Their validity is recorded separately, so a passive receiving port may retain valid impedance while its source-normalised S11 is invalid.
The group stores poles and residues together with Conductance and
Capacitance; time histories Vgenerator, Vtotal, and Inetwork;
frequency-domain Vgenerator_spectrum, Vtotal_spectrum,
Inetwork_spectrum, Iterminal_spectrum, Vincident_spectrum, and
Vreflected_spectrum; and the usual S11, Zin, Yin, mesh,
source, gap, and cells-per-wavelength validity datasets. The transform uses
the engineering convention and all three histories are sampled at the
electric half-step. NetworkModelID identifies the reusable model and
PortMode is rational_network.
The complete production update is compared with the exact reflection from series-RC and series-RLC sheets in a parallel-plate guide in Rational lumped networks in a parallel-plate guide.
A terminal owned by a subgrid is stored beneath
/subgrids/<subgrid ID>/ports/<terminal ID> using the subgrid’s fine time
and space increments.
Voltage-source S11 and impedance output
Every 3-D #voltage_source or VoltageSource Python object normally
writes one source-owned group per main-grid port at /ports/<port ID>. A
zero-resistance hard source at a domain-minimum transverse boundary remains a
valid excitation but has no automatic port group because its complete Ampere
loop is outside the model. A source added to a Python API subgrid is
stored at /subgrids/<subgrid ID>/ports/<port ID> and uses the owning
subgrid’s spatial step, time step, iteration count, material edge, and field
histories. For a finite-resistance source, its resistance is the reference
impedance \(Z_0\); the source-plane reflection coefficient is calculated
from the known generator voltage and sampled total gap voltage.
In a domain-decomposed MPI model the same schema is written after source,
receiver, and port histories have been gathered on the coordinator. All
Position and GridPosition metadata use the global main-grid frame.
For a zero-resistance hard source, \(Z_0\) is supplied by the voltage
source (50 Ohms by default) and
the terminal quantities are calculated from the prescribed voltage and
Ampere-loop current with its explicit half-step time offset. Both paths remove the effective Yee-edge
background capacitance and conductance before reporting S11, Zin, and
Yin:
For a finite-resistance source in a dispersive background, the shunt admittance uses the material’s complete complex relative permittivity, including every Debye, Lorentz, Drude, or inclusive pole,
This reduces to \(G_\mathrm{bg}+j\widetilde{\omega}C_\mathrm{gap}\) for a nondispersive conductive material. Hard voltage ports use their sampled Ampere-loop current and are not yet supported on dispersive source edges.
Hard-source port histories retain all \(N\) receiver samples, including
the initial voltage. TimeSampleOffset=0 and
CurrentTimeSampleOffset=-\Delta t/2 locate the voltage and raw loop-current
histories respectively; their Fourier transforms apply these separate offsets.
Native frequencies are based on \(N\Delta t\). Older hard-port outputs
dropped the first sample and used \(N-1\) samples with offsets
\(\Delta t\) and \(\Delta t/2\). Finite-resistance ports are unchanged:
they still use \(N-1\) half-step-aligned samples. Always use the stored
time, time_current, and frequency datasets, not an assumed length
or a frequency axis borrowed from a different port.
Important attributes include:
PortMode,ReferenceImpedance,ReferenceImpedanceSource,Polarisation,Position, andGridPosition;BackgroundMaterial,GapCapacitance, andBackgroundConductance;SpectrumLimitMode,MinimumWavelengthCells,MeshFrequencyLimit,NyquistFrequency, andLimitingMaterial;FrequencyRange(the first and last stored bins),ValidFrequencyRange(a convenience summary), andIndependentFrequencyResolution;phasor_time_sign=exp(+j*omega*t)andforward_transform_sign=exp(-j*omega*t).
Position is always expressed in the global physical coordinate frame,
including for a subgrid port, and therefore matches the associated source’s
Position attribute. GridPosition is the integer index in the owning
grid and can include the subgrid’s internal boundary padding.
The principal datasets are:
frequency: the authoritative plotting axis in Hz;S11,Zin, andYin: corrected complex terminal quantities;S11_sourceandZin_source: uncorrected source-plane quantities;Vincident_spectrum,Vreflected_source_spectrum, andVtotal_spectrum: complex voltage spectra;time,Vgenerator, andVtotal: aligned voltage audit histories;time_current,Iloop,Iloop_spectrum, andIterminal_spectrum: additional hard-source current data.Iloopis sampled at magnetic half-step times; its spectrum includes the Yee-gap admittance, while the terminal spectrum has that admittance removed;valid_S11,valid_Zin,valid_Yin,source_valid,mesh_valid, andgap_correction_valid: per-bin integer masks;incident_relative_dBandcells_per_minimum_wavelength: diagnostics behind the masks.
The normal output is capped by the requested cells-per-wavelength criterion.
With spectrum_limit='nyquist', all native non-negative bins are retained
for research, including finite values outside the recommended band, while the
validity masks and lambda/10 advisory ceiling remain present. Algebraically
undefined values are stored as complex NaNs; finite invalid values are not
silently clipped.
The frequency dataset and validity mask can be plotted directly:
import h5py
import matplotlib.pyplot as plt
import numpy as np
with h5py.File('model.h5', 'r') as output:
port = output['ports/feed']
frequency = port['frequency'][...]
s11 = port['S11'][...]
valid = port['valid_S11'][...].astype(bool)
plt.plot(frequency[valid], 20 * np.log10(np.abs(s11[valid])))
plt.xlabel('Frequency [Hz]')
plt.ylabel(r'$|S_{11}|$ [dB]')
For routine inspection, the port plotter reads these stored values and their diagnostics directly, and can save PNG, PDF, or SVG figures without repeating the terminal calculation:
python -m gprMax.toolboxes.Plotting.plot_port model.h5 --port feed --validity --save
The same command supports rational-network, transmission-line, and
magnetic-frill port groups, including ports owned by subgrids. Multiple
--port options may be supplied, or omitted to plot every discovered port.
Eigenmode-port and S-parameter output
Each explicitly numbered main-grid eigenmode source or receiver is stored
below /eigenmode_ports/portN. A direct port owned by an HSG subgrid is
stored below /subgrids/<subgrid ID>/eigenmode_ports/portN and uses that
grid’s fine dx_dy_dz, dt, and iteration count. frequency contains
the direct-DFT bins.
incident and outgoing have shape (nmodes, nfrequencies), with
rows ordered by the one-based ModeIndices attribute. With exactly one
active channel, S is the outgoing coefficient divided by that source-mode
incident coefficient, so the source group contains modal S11 and other groups
contain S21, S31, and modal-conversion terms.
Each mode has two audited anchor banks. anchor_mode_valid selects the
propagating, one-watt profiles used by TF/SF source synthesis and real-power
normalization. anchor_mode_reference_valid selects the successfully
tracked profiles used only by modal monitoring and can include evanescent
anchors. For generalized-only bins, the applicable contiguous evanescent
reference run is converted to a common E/H-balanced scale before its E, H,
and effective index are interpolated with matching branch-local weights.
Propagating and evanescent anchors are never mixed across cutoff, and
disconnected evanescent runs are not bridged. anchor_mode_propagating
records the raw forward-power classification, and anchor_balanced_power
records each raw profile’s positive balanced E/H power; its inverse square
root supplies the reference scale.
The AnchorFrequencies attribute remains the union of the retained
propagating source/power anchors, while ReferenceAnchorFrequencies is the
union of retained monitor-reference anchors. CandidateAnchorFrequencies
lists every solved candidate; use it together with
anchor_mode_reference_valid to recover the monitor-reference frequencies
for each mode rather than only their union. Non-propagating reference anchors
never drive the source and never become power waves.
For a declared degenerate group, source and reference eligibility is decided for the complete group. Non-propagating group anchors are excluded from its physical references, and failed groups do not fall back member by member. The aligned fields are authoritative for excitation, monitoring, studies, field exports, and standard modal plots.
The port’s degenerate_groups subgroup stores numbered groups with
ModeIndices, PhysicalPolarization, ReferenceAnchorIndex, and
TransverseAxes attributes. subspace_overlaps records continuity;
physically labelled groups additionally store requested_directions.
Each anchorK stores frequency, active status, eigenvalues, and eigenvalue
spread. Retained anchors additionally contain transform, residual,
and power_gram; physical alignment also records electric_moments
and its conditioning diagnostics. Rejected or inactive anchors need not
contain those aligned quantities. The recorded transformation convention is
aligned fields = raw fields @ transform.
See Degenerate subspaces and physical alignment for their definitions and thresholds.
The complex electric_cross_power_matrix and Hermitian power_matrix
both have shape
(nfrequencies, nmodes, nmodes). For a modal coefficient vector
\(c\), its spectral power is
This full quadratic form is required when finite-grid modal profiles are not
exactly orthogonal. The incident and outgoing arrays are generalized modal
travelling-wave coefficients; an individual coefficient magnitude squared is
not an additive power when power_matrix is non-diagonal. The electric
cross-power matrix is retained to reconstruct total-field flux in lossy
ports. reference_basis_valid has shape (mode, frequency) and records
tracked reference eligibility before the Gram solve. power_basis_valid
has the same shape and records forward real-power support.
coefficient_valid and power_wave_valid have shape (mode, frequency):
the first marks conditioned incident/outgoing coefficients, and the second
also requires physical power-wave support and a usable power matrix.
Single-source scattering output includes S, coefficient_valid_S, and
power_wave_valid_S, all with shape (mode, frequency). Ratio masks
additionally require a usable incident denominator above the -60 dB spectrum
floor. Below-cutoff coefficients may pass coefficient_valid_S while
failing power_wave_valid_S; their squared magnitudes are not power
fractions.
A run with one eigenmode source also writes
<output>_sparameters.csv with one row per frequency, destination port,
and destination mode. For a source in a subgrid the filename is
<output>_<subgrid ID>_sparameters.csv. Ports in different owning grids are
finalised independently and do not form one cross-grid S matrix.
When every eigenmode port has a passive virtual waveguide and no
EigenmodeExcitation is defined, the same HDF5 groups contain the raw
incident and outgoing modal spectra. No S datasets or
<output>_sparameters.csv file are written because there is no active
incident spectrum by which to normalize them.
When two or more modal channels are excited simultaneously, the groups also
contain the raw incident and outgoing spectra and have
ResponseType=driven. Source groups record ExcitationModes,
DriveAmplitudes, DrivePowers, DrivePhasesDegrees, DriveDelays,
and DriveWaveformIDs. Ordinary S datasets are not written because the
response is not an independently excited S-matrix column. Driven rows instead
store active_S=b_i/a_i, coefficient_valid_active_S, and
power_wave_valid_active_S; <output>_active_sparameters.csv contains the
same driven-state reflection data and drive weights. Use an
EigenmodeStudy for the complete state-independent matrix.
NTFF field-transformation output
Reusable KSIR and equivalent-current outputs are stored in the normal model file under their surface and transform IDs:
MPI domain-decomposition runs use this same schema and write the completed
datasets from the coordinator rank. A collection_backend value beginning
with mpi_ records that the integration surface was partitioned between
ranks; it does not change field normalisation or array ordering.
/ntff/<surface_id>/
time/<rx_id>/
points
times
time_origins
valid_lengths
fully_supported_lengths
terminal_field_ratios
terminal_decay_ok
spherical_coordinates [spherical commands only]
fields/<output>
time_far_field/<output_id>/
times
theta
phi
directions
terminal_field_ratios
terminal_decay_ok
layered_background/ [direct layered-time transforms only]
interfaces
material_ids
relative_permittivity
relative_permeability
termination/ [PEC-terminated stacks only]
observation_material_index [direct layered-time transforms only]
observation_impedance [direct layered-time transforms only]
observation_wave_speed [direct layered-time transforms only]
impulse_counts [direct layered-time transforms only]
discarded_path_amplitude_sums [direct layered-time transforms only]
fields/<output>
frequency/<transform_id>/
frequencies
layered_background/ [planar-layered transforms only]
interfaces
material_ids
relative_permittivity
relative_permeability
termination/ [PEC-terminated stacks only]
surface_dft/<component>/
field
normal_derivative
patch_positions
patch_normals
area_weights
receivers/<rx_id>/
points
spherical_coordinates [spherical commands only]
fields/<output>
far_field/<output_id>/
theta
phi
directions
radiated_power [directivity/efficiency/exterior requests]
maximum_directivity
maximum_directivity_dbi
maximum_directivity_theta
maximum_directivity_phi
exterior_regions/ [requested planar-layered summaries]
positive_to_negative_power_ratio [exterior_power]
positive_to_negative_power_ratio_db [exterior_power]
positive_axis/
relative_permittivity
relative_permeability
impedance
radiated_power [exterior_power]
radiated_fraction [exterior_power]
maximum_radiation_intensity [exterior_maximum]
maximum_directivity [exterior_maximum]
maximum_directivity_dbi [exterior_maximum]
maximum_theta [exterior_maximum]
maximum_phi [exterior_maximum]
accepted_coupling_efficiency [exterior_efficiency]
realized_coupling_efficiency [exterior_efficiency]
accepted_coupling_valid [exterior_efficiency]
realized_coupling_valid [exterior_efficiency]
maximum_gain [exterior_efficiency]
maximum_gain_dbi [exterior_efficiency]
maximum_realized_gain [exterior_efficiency]
maximum_realized_gain_dbi [exterior_efficiency]
negative_axis/ [same datasets]
port_power/ [gain/efficiency requests]
port_ids
source_types
representations
reference_impedances
incident_voltage_per_port
terminal_voltage_per_port
terminal_current_per_port
incident_power_per_port
accepted_power_per_port
incident_power
accepted_power
reflected_power
incident_relative_db
mesh_valid
terminal_valid
gain_valid
realized_gain_valid
modal_ports/ [eigenmode ports only]
port1/
mode_indices
incident
outgoing
electric_cross_power_matrix
power_matrix
valid
fields/<output>
The surface group records logical bounds, physical reference origin, closure
status, omitted faces, boundary types/coordinates, and image count.
closure=huygens_open with one to five values in omitted_faces identifies
an open frequency-domain Huygens surface; closure=symmetry identifies
faces restored by PEC/PMC image completion.
The frequency transform group records its ksir, equivalent_current,
or planar_layered_equivalent_current formulation, window, configured
precision and collection backend, plus the engineering convention:
exp(+j*omega*t) phasors, exp(-j*omega*t) forward transform, and
exp(-j*k*R) outgoing Green function.
For a planar-layered transform, layered_background records the stack
axis, positive-to-negative-axis material ordering, physical interface
coordinates, and the complex relative permittivity and permeability evaluated
at every transform frequency. The transform-level scalar wave_speed and
impedance are collection metadata for the positive-axis exterior; the
far-field group uses the appropriate observation half-space for every
direction. Its normalization attribute is therefore
r * exp(+j*k_observation_halfspace*r) * field.
For a PEC-backed stack, termination records kind=pec, its
positive or negative side, and physical position. The PEC is not
included in material_ids or the constitutive arrays. Only the open
observation side exists, so two-exterior regional datasets are absent.
Exact frequency receiver groups have range_normalized=False. They contain
physical finite-distance phasors with every 1/R and 1/R**2 term.
Far-field groups have range_normalized=True and a normalization
attribute specifying r * exp(+j*k*r) * field. Their radius is intentionally
absent. Complex datasets use the complex type paired with the configured
gprMax real precision.
The time_far_field group is produced by #ntff_time_far_field or its
array form, or by the corresponding direct layered-time commands. The
homogeneous form records formulation=equivalent_current_1997 and the
normalization r * field at reduced time t - r/c. A direct layered result
records formulation=planar_layered_equivalent_current_time, its transform
and background IDs, path tolerance and safety limit, resolved lossless stack,
observation-half-space properties, retained impulse counts, and the summed
absolute amplitudes of paths discarded at the configured threshold. Its
normalization is r * field at reduced time t - r/c_observation.
The last axis of both impulse datasets is labelled by its response_order
attribute as Vi_e, Vv_e, Vi_h, Vv_h.
Both forms record linear fractional-delay interpolation and their collection
backend. Their real field arrays have shape
(ndirections, ntimes). Er and Hr are identically zero in the
far-zone model; magnetic components are derived from
\(\mathbf H=(\hat{\mathbf r}\times\mathbf E)/\eta_o\), using the
direction-selected exterior impedance for a layered stack.
The complete definitions and the distinction between the retained Yee-time
staggering and fractional-delay interpolation are given in
Near-to-far-field transformations.
Far-field derived antenna quantities
radiation_intensity has shape (nfrequencies, ndirections). If
directivity, an efficiency, or an exterior summary is requested, the five
full-sphere summary datasets shown above have shape (nfrequencies,). The
far-field group also records the Gauss–Legendre/periodic quadrature orders and the completed
surface’s bounding radius in metres. These summaries come from an internal
full-sphere calculation even if the stored user directions form only a cut;
the internal directional fields are not written to the output file. The
maximum is refined using the directions in that particular output whenever
they sample a larger value than the internal quadrature.
The linear definitions are
For homogeneous transforms \(\eta_o\) is constant. For a planar stack it is the real impedance of the positive- or negative-axis lossless exterior, selected by the observation direction.
directivity_dbi, gain_dbi, and realized_gain_dbi are
10*log10 of their corresponding linear datasets. The linear gain and
efficiency definitions are
The two efficiencies are frequency-only quantities and therefore have shape
(nfrequencies,) even though they are stored in fields with the other
requested outputs.
Planar-layered exterior-region antenna quantities
The grouped exterior_power, exterior_maximum, and
exterior_efficiency requests are available only for a
planar_layered_equivalent_current transform. They divide the temporary
full-sphere quadrature according to the sign of the direction cosine along
the declared stack axis. The names positive_axis and negative_axis
are used deliberately: gprMax does not assume that the stack is aligned with
z or that either exterior represents air or ground.
For exterior region \(r\in\{+,-\}\),
exterior_power stores \(P_r\), \(f_r\), and
\(P_+/P_-\) in linear and dB forms. A zero denominator consequently
produces the mathematically corresponding non-finite ratio. The constituent
material ID is an attribute of each region; its frequency-dependent relative
permittivity, relative permeability, and real wave impedance are datasets.
exterior_maximum stores the maximum radiation intensity found in each
region and its angles. Its directivity retains the conventional total-power,
full-sphere definition
It is not the non-standard hemisphere-normalised quantity \(2\pi U/P_r\). As for the global maximum, the estimate combines the internal quadrature with all explicitly requested directions.
With an #ntff_antenna_ports association, exterior_efficiency stores
and the maximum gain and realized gain in each exterior:
The coupling-efficiency names distinguish these regional quantities from the
total radiation and total efficiencies. The corresponding validity masks use
the same mesh, terminal, incident-spectrum, and positive-power checks as the
ordinary gain outputs. Summing the two accepted coupling efficiencies gives
radiation_efficiency; summing the two realized coupling efficiencies gives
total_efficiency wherever those quantities are valid.
For a #ksir_antenna_ports or #ntff_antenna_ports association, per-port
powers have shape (nports, nfrequencies). Total powers and all validity
masks have shape (nfrequencies,). Eigenmode ports can normalize either a
closed KSIR or equivalent-current transform. KSIR rejects an open surface,
regardless of source type. Here nfrequencies is the transform frequency
count: when the eigenmode DFT grid is denser, the per-port modal arrays in the
far-field port_power group contain only the matching transform subset. The
complete modal grid remains in the top-level eigenmode-port group.
Conventional terminal ports use
For a modal port with incident and outgoing vectors \(a_p\) and \(b_p\), define \(x_p=a_p+b_p\) and \(y_p=a_p-b_p\). With electric cross-power matrix \(G^E_p\), the co-located total-field flux is
The incident power of an eigenmode source is the quadratic power of its externally excited mode only. A passive eigenmode receiver has zero generator incident power. Totals are
These are spectral power-normalisation quantities: the voltage and field
Fourier transforms carry a common time scale, which cancels in gain and
efficiency. Their HDF5 attributes consequently give voltage spectra in
V s, current spectra in A s, and spectral powers in W s**2. The
exact complex terminal and incident spectra are retained so that every
derived power can be checked independently. For modal ports those terminal
arrays and reference impedance are NaN because no artificial voltage/current
equivalent is introduced; representations identifies them as
modal_power_waves (the retained schema identifier), and modal_ports
retains the generalized modal amplitudes, electric cross-power matrix, and
Hermitian forward-wave power matrix. Where the real-power masks are true,
modal amplitudes have units sqrt(W) s and their dimensionless quadratic
matrices produce W s**2 spectral power. A finite coefficient outside that
mask is a generalized reference-basis amplitude only; its magnitude squared
is not power. A zero-amplitude
conventional source remains a terminated port with zero incident voltage; its
terminal voltage/current and signed accepted power can still be non-zero
through mutual coupling.
The port_ids dataset stores main-grid IDs unchanged and qualifies subgrid
ports as <subgrid ID>/<local port ID>. Although the grouped antenna result
is written below the main-grid NTFF group, each port spectrum is calculated
with the spatial step, time step, and trace length of the grid that owns it.
terminal_valid is also the combined modal-power validity
mask when a modal port is present. The validity datasets should always be
applied before plotting. The default
gain bandwidth includes frequencies whose total incident spectrum is within
40 dB of its peak and for which the mesh and port reconstruction are
valid. Invalid derived results are stored as NaN rather than a plausible
but ill-conditioned value.
When requested, far_field/<output_id>/fields/rcs contains real, linear
bistatic radar cross section in square metres. It is not stored in dBsm. For
the range-normalized scattered electric field
\(F_\mathrm{s}=r\exp(+jkr)E_\mathrm{s}\), gprMax calculates
The denominator is obtained from the actual field history in the associated
discrete-plane-wave grid, accumulated at the transform frequencies with the
same time window as the surface data. It therefore includes the numerical
plane-wave amplitude and its configured start and stop times. A zero incident
spectrum produces NaN RCS. Very small incident values are mathematically
non-zero but can give unreliable results, so the requested frequencies should
remain within the useful excitation bandwidth.
When a frequency transform is associated with a plane wave, its
plane_wave subgroup stores the source index, TFSF corners, waveform and
material IDs, actual angles, polarisation, rational integer mapping, start and
stop times, and the incident-field reference positions. This metadata is the
authoritative description of the illumination used for that transform.
For plotting in dBsm, convert the stored values explicitly:
import h5py
import numpy as np
with h5py.File('model.h5', 'r') as output:
far = output['ntff/surface/frequency/transform/far_field/backscatter']
rcs = far['fields/rcs'][...] # linear RCS in m**2
rcs_dbsm = 10 * np.log10(rcs)
Here theta and phi in the same group define the observation direction.
Monostatic RCS is the value in the direction opposite to plane-wave
propagation; all other directions are bistatic RCS. Use separate simulations
for different incident plane waves because selecting an association does not
separate simultaneously accumulated scattered fields. A
gprMax.PlaneWaveStudy automates those separate illuminations while
reusing the unchanged Yee geometry.
Exact finite-distance KSIR time-domain fields retain the complete raw retarded
buffer and have shape (npoints, max(valid_lengths)). Its final bins may contain only part of the
closed-surface history because different surface patches have different
propagation delays. For normal use, point q must therefore be sliced with
fully_supported_lengths:
length = fully_supported_lengths[q]
physical_time = time_origins[q] + times[:length]
trace = fields[output][q, :length]
valid_lengths remains available for research access to every stored bin.
Those additional bins are not a complete field reconstruction unless the
surface fields had already decayed to zero. terminal_field_ratios gives,
for each point, the largest ratio between the final 32 fully supported samples
and the trace peak, evaluated independently for each underlying Cartesian
component. terminal_decay_ok is true when this is no greater than
terminal_decay_threshold (stored as a group attribute). gprMax emits a
warning when the test fails; increasing the model time window is the correct
remedy.
With time_origin=simulation every origin is zero. With
time_origin=first_arrival each origin retains its absolute propagation
time without storing the potentially large guaranteed leading-zero prefix.
For this origin policy, fully_supported_lengths normally equals the number
of FDTD iterations.
Equivalent-current transient far fields use a stricter output policy. Their
times dataset already contains only the common interval for which every
surface patch has an available retarded-time sample; no partially supported
tail is written. The time coordinate is reduced time
\(\tau=t-r/c_b\), referenced to the surface origin, so increasing a
hypothetical observation radius would not prepend zeros. The
terminal_field_ratios and terminal_decay_ok datasets are per direction.
A false value means the FDTD time window should be increased.
The surface DFT datasets are present by default and allow later angular or point evaluation without rerunning FDTD. They can be large: their leading dimensions are frequency and surface patch. An NTFF output creates the normal model output file even when there are no conventional receivers or transmission lines.
NTFF surfaces must strictly enclose every impressed source. For plane-wave scattering models, the associated total-field/scattered-field box must be strictly enclosed by the NTFF surface. The integration surface then samples the scattered-field region outside the TFSF box, while the associated numerical plane wave supplies the incident-field normalization used for RCS. Sources and scatterers may reside on an HSG subgrid enclosed by these main-grid surfaces. Neither an NTFF surface nor a TFSF correction surface may touch or cut the HSG outer coupling surface; an overlapping surface must strictly enclose the complete subgrid coupling region.
Surface-impedance reproducibility metadata
Every output file containing a surface definition has a root group
/surface_impedance_models. Its attributes are:
SchemaVersion = 3;TimeConvention = exp(+j*omega*t);FourierAnalysisConvention = exp(-j*omega*t);SurfaceNormalConvention = metal_to_retained_dielectric;SurfaceCurrentConvention = K = n_m cross H;Units = SI;FDTDTimeStep.
Each definition appears as model1, model2, and so on, in definition
order. A model group stores ID, ModelHashSHA256, Order, D, fit
limits, source kind, conductivity, preset/provenance, requested and selected
pole counts, fit method and tolerance, maximum/RMS errors, plotting policy, and
whether the compiled boundary uses it. The continuous A, B, and C
arrays are datasets. A preset additionally stores reference temperature and
resistivity.
For every model used by the compiled boundary, fdtd_discrete stores the
exact local f and q pole vectors and the TimeStep, Z0, and
PassivityChecked attributes. Together with the continuous realization,
these reproduce both the in-place FDTD recurrence and the equivalent FDFD
transfer. A defined but unused model has no discrete subgroup. The model hash
covers the continuous model and fitting provenance. The current schema does
not serialize the complete
sparse geometry/port map, so geometry reproducibility still depends on the
input model and normal gprMax output metadata.
An eigenmode port additionally stores anchor_complex_neff below its
/eigenmode_ports/portN group. Its complex array has shape
(anchor frequency, mode) and is aligned with the
CandidateAnchorFrequencies attribute. The associated
anchor_mode_valid and anchor_mode_reference_valid datasets identify
the usable rows. This is the exact FDFD propagation constant bank used for
broadband interpolation and makes the FDFD attenuation comparison
reproducible from the output file.
For example, inspect one used realization with:
import h5py
with h5py.File('model.h5', 'r') as output:
models = output['surface_impedance_models']
wall = models['model1']
print(wall.attrs['ID'], wall.attrs['ModelHashSHA256'])
A = wall['A'][...]
B = wall['B'][...]
C = wall['C'][...]
f = wall['fdtd_discrete/f'][...]
q = wall['fdtd_discrete/q'][...]
Z0 = wall['fdtd_discrete'].attrs['Z0']
Snapshots
Snapshot files contain a snapshot of the electromagnetic field values of a specified volume of the model domain at a specified point in time during the simulation. By default, snapshot files use version 2.2 of the open source Visualization ToolKit (VTK) VTKHDF format. ParaView 5.12 or newer is required to view these files; the gprMax macro has been tested directly with ParaView 6.0.1. ParaView is an open-source, multi-platform data analysis and visualization application available for Linux, macOS, and Windows. You can optionally output snapshot files using the HDF5 format if desired. HDF5 snapshots include origin (global x, y, z coordinates), dx_dy_dz, nx_ny_nz, iteration, time, and magnetic_time attributes. time is the electric-field time \(n\Delta t\), and magnetic_time is the native staggered magnetic-field time \((n-1/2)\Delta t\); no temporal averaging is applied. A snapshot owned by an HSG subgrid uses its fine-grid iteration and time step and is still positioned in this global coordinate frame.
A requested real time is rounded to the nearest full electric-field step (halfway values round to the earlier step). An integer iteration selects that same zero-based level directly, so the two input forms produce the same field state. Valid indices are zero through one less than the owning grid’s number of iterations. Spatial collocation of the staggered Yee components within a snapshot cell is a separate operation and is unchanged by this timing rule.
All main-grid and subgrid snapshots for a model are written into the same
snapshot directory. If two snapshots resolve to exactly the same filename,
gprMax issues a warning because the later output will overwrite the earlier
one. The comparison includes the file extension, so the same base name may be
used safely for different formats, for example fields.h5 and
fields.vtkhdf.
For a reduced 2-D model, a snapshot contains only the genuine invariant-axis field plane: index zero for TM and index one for TE. Bounds spanning the full invariant extent are collapsed automatically to that plane; bounds excluding it are rejected. Inactive components may still be requested for a consistent file schema, but contain zero. The file origin places the centre of the single output plane at the physical Yee-field plane, rather than at either forced-zero TE padding wall.
Tip
You can take advantage of our Python API to easily create a series of snapshots. For example, to create 30 snapshots starting at time 0.1ns until 3ns in intervals of 0.1ns, use the following code snippet in your input file. Replace x, y, z, dl, fn accordingly.
import gprMax
for i in range(1, 31):
s = gprMax.Snapshot(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
time=(i/10) * 1e-9,
filename=fn.with_suffix('').parts[-1] + '_' + str(i))
scene.add(s)
The following are steps to get started with viewing snapshot files in Paraview:
Open the file either from the File menu or toolbar. Paraview should recognise the time series based on the file name and load in all the files.
Click the Apply button in the Properties panel. You should see an outline of the snapshot volume.
Use the Coloring drop down menu to select the field component you want to visual, e.g. Ex, Ey, Ez, Hx, Hy, Hz.
From the Representation drop down menu select Surface.
You can step through or play as an animation the time steps using the time controls in the toolbar.
Tip
Turn on the Animation View (View->Animation View menu) to control the speed and start/stop points of the animation.
Use the Color Map Editor to adjust the Color Scaling.
Geometry output
Geometry files use version 2.2 of the open source Visualization ToolKit (VTK) VTKHDF format. ParaView 5.12 or newer is required to view these files; the gprMax macro and its source/receiver representations have been tested directly with ParaView 6.0.1. ParaView is an open-source, multi-platform data analysis and visualization application available for Linux, macOS, and Windows.
The #geometry_view: command produces either ImageData for a per-cell geometry view, or UnstructuredGrid for a per-cell-edge geometry view. The following are steps to get started with viewing geometry files in Paraview:
If the model contains semantic geometry tags, a normal per-cell geometry view
also contains the integer cell array TagID. VTKHDF field data stores the
matching geometry_tag_ids and geometry_tag_names arrays; ID zero means
untagged. The tag array records the final voxelised geometry after ordered
overwrites and is not affected by dielectric smoothing. It is omitted
entirely for models without tags. Per-cell-edge geometry views do not export
tags because zero-thickness edge and plate objects do not yet have tag
semantics.
Both normal and fine geometry views contain typed catalogues of active sources and receivers. Localised sources and receiver ports are represented by one cell-sized marker at their grid position. A discrete plane-wave source is represented by the boundary of its TFSF box (a rectangle in a reduced 2-D model), while an eigenmode port is represented by its aperture plane. Virtual waveguides use that same physical aperture and are identified as virtual- waveguide interfaces.
Port roles are determined from the resolved excitation used by that model run.
A voltage-source, transmission-line, magnetic-frill, or network port whose
resolved drive is identically zero is a receiver, not a source. An active
eigenmode port is a source and a passive eigenmode port is a receiver. Ordinary
Rx points, including points expanded from an RxArray, are receivers;
the private sampling receiver belonging to a voltage-source port is not shown
again at the same position. NTFF and KSIR observation locations are deliberately
omitted because they describe transformations or observation points outside
the FDTD geometry rather than receiver placement within the model.
The source catalogue is stored in the source_geometry_ids,
source_geometry_types, source_geometry_kinds, and
source_geometry_bounds field arrays. The receiver catalogue uses the
corresponding receiver_geometry_* names. The gprMax ParaView macro creates
the point boxes, wireframe TFSF boundaries, and port plates, and prefixes each
Pipeline Browser name with Source or Receiver followed by its type and
ID.
Fig. 19 Paraview toolbar showing gprMax macro button.
Open the file either from the File menu or the toolbar.
Click the Apply button in the Properties panel. You should see an outline of the volume of the geometry view.
Install the
gprMax.pyPython script, that comes with the gprMax source code (in thegprMax/toolboxes/Utilities/Paraviewdirectory), as a macro in Paraview. This script makes it quick and easy to view the different materials in a geometry file. To add the script as a macro in Paraview choose the file from the Macros->Add new macro menu. It will then appear as a shortcut button in the toolbar as shown in Fig. 19. You only need to do this once, the macro will be kept in Paraview for future use.Click the
gprMaxshortcut button. All the materials in the model should appear in the Pipeline Browser as Threshold items as shown in Fig. 20. If the geometry contains semantic tags, the macro also createsTag - <name>Threshold items. These are hidden initially to avoid obscuring the material view and can be enabled individually with the eye icon.
Fig. 20 Paraview Pipeline Browser showing list of materials in an example model.
Tip
You can turn on and off the visibility of materials using the eye icon in the Pipeline Browser. You can select multiple materials using the Shift key, and by shift-clicking the eye icon, turn the visibility of multiple materials on and off.
You can set the Color and Opacity of materials from the Properties panel.