Advanced Model Building (Python API)
Introduction
Practical workflows are in Sources and ports and Reusable studies. The entries here describe the model objects and include their output contracts; complete HDF5 schemas are in Model Output.
gprMax has a choice of two methods for building a model to simulate:
A text-based (ASCII) input file, which can be created with any text editor, and uses a series of gprMax commands which begin with the hash character (
#). This method is recommended for beginners and those not familiar with Python, and is described in the Model Building section.A Python API, which includes all the functionality of method 1 as well as several more advanced features. This method is recommended for those who prefer to use Python or need access to specific API-only advanced features, and is described in this section of the documentation.
The Python API in gprMax allows users to access gprMax functions directly from Python by importing the gprMax module. There are several advantages to using the API:
Users can take advantage of the Python language - for instance, the structural elements of Python can be utilised more easily.
gprMax objects can be used directly within functions, classes, modules and packages. In this way collections of components can be defined, reused and modified. For example, complex targets can be imported from a separate module and combined with an antenna from another module.
The API can interface with other Python libraries. For example, the API could be used to create a parametric antenna and the external library Scipy could then be used to optimise its parameters.
The API syntax is generally more verbose than the hash-command syntax. However, for commands with a variable number of parameters, such as those that add dispersive properties, the API may be more manageable.
Keyword names are checked when a model object is constructed. Unknown
keywords raise TypeError, including when their value is None,
False, zero, or an empty string. For example, averagin=False is an
error; use averaging=False. This also applies to optional optimisation
parameters in the GPR antenna toolbox. No spelling is corrected automatically.
Use the parameters documented for the particular command or antenna.
Source/receiver positions and output bounds containing inf are resolved
against each grid when it is built. The declaration retains its symbolic
coordinates, so reusing it with a different grid spacing or domain does not
freeze the first build’s resolved position. This refers to independent full
model builds; geometry_fixed and study reuse do not change an existing
grid’s discretisation.
str(user_object) is a readable, hash-command-style diagnostic, not a general
API-to-input-file exporter. In particular, omitted optional fields do not
always round-trip through the positional hash-command syntax. Use the
documented command syntax when writing an input file.
Note
In prior versions of gprMax (<4) the input file could be scripted using Python inserted between two commands (#python: and #end_python:). This feature is now deprecated and will be removed entirely in later versions. Users are encouraged to move to the new Python API. Antenna models can still be inserted between #python: and #end_python: commands but will need to make a small change to their input file. An example of this is provided in examples/gpr/antennas/gssi_1500/antenna_like_GSSI_1500_fs.in. Alternatively a switch to the Python API can be made using the adjacent examples/gpr/antennas/gssi_1500/antenna_like_GSSI_1500_fs.py example.
Example
The equivalent hash-command model is
antenna_wire_dipole_fs.in.
This example is used to give an introduction to the gprMax Python API.
1"""Half-wavelength wire dipole excited by a one-cell voltage-source port.
2
3The source-owned port calculates and stores frequency, corrected complex
4S11, input impedance, and input admittance under ``/ports/feed`` in the model
5HDF5 output. No post-processing of source voltage and current is required.
6"""
7
8from pathlib import Path
9
10import gprMax
11
12fn = Path(__file__)
13
14scene = gprMax.Scene()
15scene.add(gprMax.Title(name=fn.stem))
16scene.add(gprMax.Domain(p1=(0.050, 0.050, 0.200)))
17scene.add(gprMax.Discretisation(p1=(0.001, 0.001, 0.001)))
18scene.add(gprMax.TimeWindow(time=60e-9))
19scene.add(gprMax.Waveform(wave_type="gaussian", amp=1, freq=1e9, id="mypulse"))
20scene.add(
21 gprMax.Edge(
22 p1=(0.025, 0.025, 0.025),
23 p2=(0.025, 0.025, 0.175),
24 material_id="pec",
25 )
26)
27scene.add(
28 gprMax.Edge(
29 p1=(0.025, 0.025, 0.100),
30 p2=(0.025, 0.025, 0.101),
31 material_id="free_space",
32 )
33)
34scene.add(
35 gprMax.VoltageSource(
36 p1=(0.025, 0.025, 0.100),
37 polarisation="z",
38 resistance=50,
39 waveform_id="mypulse",
40 id="feed",
41 )
42)
43scene.add(
44 gprMax.GeometryView(
45 p1=(0.020, 0.020, 0.020),
46 p2=(0.030, 0.030, 0.180),
47 dl=(0.001, 0.001, 0.001),
48 filename=fn.stem,
49 output_type="f",
50 )
51)
52
53gprMax.run(scenes=[scene], n=1, outputfile=fn)
Import the gprMax module.
Objects for the model are created from the gprMax module by passing object parameters as key=value arguments. The adjacent
.inmodel shows their equivalent positional hash commands.Create a
gprMax.scene.Sceneobject. The scene is a container for all the objects required in a simulation. Simulations with multiple models, e.g. A-scans, should have a separate scene for each model (A-scan). Each scene must contain the essential functions and objects required for that particular model.Add objects are to the scene.
Run the simulation.
Unless otherwise specified, the SI system of units is used throughout gprMax:
All parameters associated with simulated space (i.e. size of model, spatial increments, etc…) should be specified in metres.
All parameters associated with time (i.e. total simulation time, time instants, etc…) should be specified in seconds.
All parameters denoting frequency should be specified in Hertz.
All parameters associated with spatial coordinates in the model should be specified in metres. The origin of the coordinate system (0,0) is at the lower left corner of the model.
It is important to note that gprMax converts spatial and temporal parameters given in metres and seconds to integer values corresponding to FDTD cell coordinates and iteration number respectively. Therefore, rounding to the nearest integer number of the user defined values is performed.
The fundamental spatial and temporal discretization steps are denoted as \(\Delta x\) , \(\Delta y\), \(\Delta z\) and \(\Delta t\) respectively.
The functions have been grouped into six categories:
Essential - required to run any model, such as the domain size and spatial discretization
General - provide further control over the model
Material - used to introduce different materials into the model
Object construction - used to build geometric shapes with different constitutive parameters
Source and output - used to place source and output points in the model
PML - provide advanced customisation and optimisation of the absorbing boundary conditions
Essential functions
Most of the functions are optional but there are some essential functions which are necessary in order to construct any model. For example, none of the media and object functions are necessary to run a model. However, without specifying any objects in the model gprMax will simulate free space (air), which on its own, is not particularly useful for GPR modelling. If you have not specified a functions which is essential in order to run a model, for example the size of the model, gprMax will terminate execution and issue an appropriate error message.
The essential functions are:
Running model(s)
- gprMax.run(scenes=None, inputfile=None, outputfile=None, n=1, i=None, taskfarm=False, mpi=None, gpu=None, opencl=None, metal=None, cpu_precision='single', gpu_precision='single', subgrid=False, autotranslate=False, geometry_only=False, geometry_fixed=False, study=None, write_processed=False, show_progress_bars=False, hide_progress_bars=False, log_level=20, log_file=False, log_all_ranks=False, allow_underresolved=False)
Entry point for application programming interface (API).
Runs the simulation for the given list of scenes.
- Parameters
scenes – list of the scenes to run the model. Multiple scene objects can be given in order to run multiple simulation runs. Each scene must contain the essential simulation objects.
inputfile – optional string for input file path. Can also run simulation by providing an input file.
outputfile – string for file path to the output data file
n – optional int for number of required simulation runs.
i – optional int for model number to start/restart simulation from. For ordinary runs, n is the number of models to execute, not the final model number: i=45, n=16 runs A-scans 45 through 60. Study-managed case counts follow the study’s restart rules.
taskfarm – optional boolean flag to use Message Passing Interface (MPI) task farm. This option is most usefully combined with n to allow individual models to be farmed out using a MPI task farm, e.g. to create a B-scan with 60 traces and use MPI to farm out each trace. For further details see the performance section of the User Guide.
mpi – optional flag to use Message Passing Interface (MPI) to divide the model between MPI ranks. Three integers should be provided to define the number of MPI processes (min 1) in the x, y, and z dimensions.
gpu – optional list/boolean to use NVIDIA GPU or list of NVIDIA GPU device ID(s) for specific GPU card(s).
opencl – optional list/boolean to use OpenCL or list of OpenCL device ID(s) for specific compute device(s).
metal – optional list/boolean to use Apple Metal or list of Apple Metal GPU device ID(s) for specific GPU card(s).
cpu_precision – optional string, “single” or “double”, precision for the CPU solver. Defaults to “single” to preserve memory - ignored if a GPU solver is used. Refining subgrids force double; ratio-one equal-resolution regions inherit this setting.
gpu_precision – optional string, “single” or “double”, precision for the CUDA/OpenCL/Metal solvers. Defaults to “single”. Ignored if the CPU solver is used. Subgridding is currently CPU-only.
subgrid – optional boolean to use sub-gridding.
autotranslate – optional boolean for sub-gridding to auto translate objects with main grid coordinates to their equivalent local grid coordinate within the subgrid. If this option is off users must specify sub-grid object point within the global subgrid space.
geometry_only – optional boolean to build a model and produce any geometry views but do not run the simulation.
geometry_fixed – optional boolean to run a series of models where the geometry does not change between models.
study – optional Study instance defining validated per-run object states while reusing one geometry.
write_processed – optional boolean to write another input file after any #python blocks (which are deprecated) in the original input file has been processed.
show_progress_bars – optional boolean to force progress bars to be displayed - by default, progress bars are displayed when the log level is info (20) or less.
hide_progress_bars – optional boolean to force progress bars to be hidden - by default, progress bars are hidden when the log level is greater than info (20).
log_level – optional int for level of logging to use.
log_file – optional boolean to write logging information to file.
log_all_ranks – optional boolean to write logging information from all MPI ranks. Default behaviour only provides log output from rank 0. When used with –log-file, each ran will write to an individual file.
allow_underresolved – optional boolean, default False. Warn rather than stop when the pre-solve wavelength-sampling check finds insufficient spatial resolution. This research override does not change the mesh, timestep, material stability checks or frequency-domain output-validity limits.
For deliberate mesh-resolution experiments, allow_underresolved=True changes
the pre-solve wavelength-sampling rejection into a warning. The default is
False; material stability and output-validity checks remain enabled. See
spatial-resolution diagnostic for the scope of this override and the
exclusion of zero-amplitude passive-source waveforms.
Creating a model scene
Domain
Domain Mode
- class gprMax.user_objects.cmds_singleuse.DomainMode(mode: str)
Declares the domain mode for the model: 2D TM, 2D TE, or 3D.
Optional. Only required when the model uses inf on the invariant axis of #domain (and consequently on that axis in position-taking commands) to build a 2D model without the user having to compute the axis extent by hand. “3D” is accepted explicitly, even though it is also the default with no #domain_mode command present, so that a model can be switched between 2D and 3D by changing this command’s argument alone, without having to remove the command.
- requested_mode
Requested domain mode, “TM”, “TE” or “3D”.
- Type
str
For an explicit 2D model, set one component of Domain.p1 to
float('inf') and add DomainMode('TM') or DomainMode('TE') before
the domain is built. The infinite value identifies the invariant axis; it is
resolved internally to the one-cell TM or two-cell TE Yee-grid thickness.
scene.add(gprMax.Discretisation(p1=(0.002, 0.002, 0.002)))
scene.add(gprMax.DomainMode(mode='TE'))
scene.add(gprMax.Domain(p1=(0.24, 0.21, float('inf'))))
Discretisation
Time Window
- class gprMax.user_objects.cmds_singleuse.TimeWindow(time: Optional[float] = None, iterations: Optional[int] = None)
Specifies the total required simulated time.
Either time or iterations must be specified. If both are specified, time takes precedence.
- time
Simulated time in seconds.
- Type
float | None
- iterations
Number of iterations.
- Type
int | None
A minimal three-dimensional scene contains the three essential model objects:
scene = gprMax.Scene()
scene.add(gprMax.Domain(p1=(0.30, 0.20, 0.15)))
scene.add(gprMax.Discretisation(p1=(0.002, 0.002, 0.002)))
scene.add(gprMax.TimeWindow(time=12e-9))
gprMax.run(scenes=[scene], n=1, outputfile='minimal_model')
General functions
Title
Number of OpenMP threads
Time Step Stability Factor
- class gprMax.user_objects.cmds_singleuse.TimeStepStabilityFactor(f: float)
Factor by which to reduce the time step from the CFL limit.
A Scene declaring SurfaceImpedance caps the effective factor at 0.99 before time-dependent objects are built, preserving smaller user values.
- stability_factor
Factor to multiply time step by.
- Type
float
Declaring SurfaceImpedance automatically caps the effective factor at
0.99, preserves any smaller user factor, and reports an automatic reduction
in the build log. See Automatic time-step margin.
Dispersive materials also undergo the Dispersive-material timestep check before
time stepping. If it fails, the run stops without changing the chosen timestep
or material parameters. Use TimeStepStabilityFactor(f=...) to explicitly
request a smaller timestep; the diagnostic gives a checked candidate when
one is found.
Output Directory
- class gprMax.user_objects.cmds_singleuse.OutputDir(dir: str)
Set the directory where output file(s) will be stored.
- output_dir
File path to directory. Relative Python API paths are resolved against the working directory at build time. Hash commands resolve them against the top-level input file instead.
- Type
str
Relative OutputDir(dir=...) paths are resolved against the working directory
when the Scene is built. This differs from paths in the #output_dir hash command, which are
relative to the top-level input file. The resolved directory is retained during
geometry_fixed=True repetition, with distinct numbered model and snapshot
paths.
Magnetic Averaging
- class gprMax.user_objects.cmds_singleuse.MagneticAveraging(mode: str = 'harmonic')
Sets the mixing rule used to combine the relative magnetic permeability (mu_r) and magnetic loss (sigma*) of two different materials when a magnetic (H) field component’s Yee-cell smoothing needs to average across a material boundary.
Optional. Defaults to ‘harmonic’. Each H component (Hx, Hy, Hz) is averaged from the two neighbouring cells stacked along the component’s own axis, i.e. normal to any interface between them. The normal component of B is continuous across a material interface, so the harmonic mean of mu_r (and, for consistency, sigma*) is the physically correct mixing rule for this direction - unlike the tangential 4-cell average used for E-field smoothing, where the arithmetic mean already used remains correct and is unaffected by this command.
Versions of gprMax prior to the introduction of this command always used a simple arithmetic mean here instead. Set this command to ‘arithmetic’ to reproduce that older behaviour exactly, e.g. to reproduce results generated with an older version of gprMax.
- mode
‘harmonic’ (default) or ‘arithmetic’.
- Type
str
Dispersive Averaging
- class gprMax.user_objects.cmds_singleuse.DispersiveAveraging(enabled: bool = True)
Enable or disable arithmetic interface averaging for dispersive media.
When enabled, Debye, Lorentz, and Drude materials participate in the four-cell electric-edge averaging used for nondispersive dielectric materials. The exact effective material retains every distinct inclusive pole and scales each residue by its cell weight. Ordinary dielectric smoothing remains controlled by the
averagingargument of each volumetric object.This option is disabled by default because the compound material can have more poles than its constituents, increasing model-wide dispersive memory.
- enabled
Whether dispersive interface averaging is enabled.
- Type
bool
Reusable parameter studies
See Reusable studies for the task-selection guide, case semantics, restrictions,
CSV/Python examples, result types and restart behaviour.
gprMax.Study, gprMax.StudyCase and
gprMax.ObjectState define the common scheduling interface.
- class gprMax.studies.Study(type: str, cases: Sequence[StudyCase], *, source_path: Optional[Union[Path, str]] = None, source_text: Optional[str] = None)
A sequence of cases evaluated while reusing one built geometry.
Fixed-topology terminal-source studies
SourceStudy schedules fixed transmission-line, frill and rational-network generators without removing their passive loads.
- class gprMax.studies.SourceStudy(cases: Sequence[StudyCase], *, source_path: Optional[Union[Path, str]] = None, source_text: Optional[str] = None)
Reusable study for fixed-topology stateful terminal sources.
Transmission-line resistance, magnetic-frill geometry/Z0, and rational network topology remain fixed. Cases may select the active generators and change only their waveform, time window, and scale. An omitted or inactive source retains its physical terminal with a zero generator drive.
Finite-resistance voltage-port studies
PortStudy computes a complete S matrix from finite-resistance voltage ports. Hard sources are not matched terminations.
- class gprMax.studies.PortStudy(cases: Sequence[StudyCase], *, source_path: Optional[Union[Path, str]] = None, source_text: Optional[str] = None)
One-active-port-per-case finite-resistance voltage-source study.
- class gprMax.studies.PortStudyResult(frequency: NDArray[floating], port_ids: tuple[str, ...], source_ids: tuple[str, ...], case_ids: tuple[str, ...], reference_impedance: NDArray[floating], gap_correction: NDArray[complexfloating], s_source: NDArray[complexfloating], s: NDArray[complexfloating], valid_s_source: NDArray[bool], valid_s: NDArray[bool], output_file: Path)
Assembled source-plane and gap-corrected multiport S parameters.
- frequency
frequency axis in Hz with shape
(F,).- Type
NDArray[numpy.floating]
- port_ids
output-port ordering used by both S-matrix port axes.
- Type
tuple[str, …]
- source_ids
voltage-source identifiers corresponding to
port_ids.- Type
tuple[str, …]
- case_ids
study-case ordering used for the driven input columns.
- Type
tuple[str, …]
- reference_impedance
real port impedances in ohms with shape
(P,).- Type
NDArray[numpy.floating]
- gap_correction
dimensionless parallel gap admittance with shape
(F, P).- Type
NDArray[numpy.complexfloating]
- s_source
uncorrected source-plane S matrix with shape
(F, P, P).- Type
NDArray[numpy.complexfloating]
- s
gap-corrected S matrix with shape
(F, P, P); its axes are(frequency, output_port, input_port).- Type
NDArray[numpy.complexfloating]
- valid_s_source
validity mask for
s_source.- Type
NDArray[numpy.bool]
- valid_s
validity mask for
s.- Type
NDArray[numpy.bool]
- output_file
aggregate study HDF5 path.
- Type
pathlib.Path
Eigenmode-port studies and array synthesis
EigenmodeStudy provides modal S matrices,
gprMax.ArrayCodebook states and embedded far-field synthesis.
- class gprMax.studies.EigenmodeStudy(cases: Sequence[StudyCase], *, codebook: Optional[ArrayCodebook] = None, source_path: Optional[Union[Path, str]] = None, source_text: Optional[str] = None)
One-active-modal-channel-per-case reusable eigenmode-port study.
All transverse modal anchor problems are solved during the first geometry build. Later cases only synthesize an injection from those cached bases, clear modal/virtual-guide state, and select a new active
(port, mode).
- class gprMax.studies.EigenmodeStudyResult(frequency: NDArray[~numpy.floating], channel_ports: NDArray[~numpy.integer], channel_modes: NDArray[~numpy.integer], case_ids: tuple[str, ...], s: NDArray[~numpy.complexfloating], power_wave_valid_s: NDArray[~numpy.bool], coefficient_valid_s: NDArray[~numpy.bool], output_file: ~pathlib.Path, embedded_far_fields: ~typing.Mapping[str, ~gprMax.studies.EmbeddedFarFieldBank] = <factory>, incident_matrix: ~typing.Optional[NDArray[~numpy.complexfloating]] = None, outgoing_matrix: ~typing.Optional[NDArray[~numpy.complexfloating]] = None, power_wave_valid_matrix: ~typing.Optional[NDArray[~numpy.bool]] = None, coefficient_valid_wave_matrix: ~typing.Optional[NDArray[~numpy.bool]] = None, deembedding_condition_number: ~typing.Optional[NDArray[~numpy.floating]] = None, deembedding_valid: ~typing.Optional[NDArray[~numpy.bool]] = None)
Assembled modal S matrix from one active port/mode per run.
- frequency
frequency axis in Hz with shape
(F,).- Type
NDArray[numpy.floating]
- channel_ports
one-based port number for each modal channel.
- Type
NDArray[numpy.integer]
- channel_modes
one-based mode number for each modal channel.
- Type
NDArray[numpy.integer]
- case_ids
identifiers of the independent excitation cases.
- Type
tuple[str, …]
- s
generalized modal S matrix with shape
(F, C, C)and axes(frequency, output_channel, input_channel).- Type
NDArray[numpy.complexfloating]
- power_wave_valid_s
physical propagating-power validity mask for
s.- Type
NDArray[numpy.bool]
- coefficient_valid_s
generalized-coefficient validity mask for
s.- Type
NDArray[numpy.bool]
- output_file
aggregate study HDF5 path.
- Type
pathlib.Path
- embedded_far_fields
mapping from
transform_id/output_idto de-embeddedEmbeddedFarFieldBankobjects.- Type
Mapping[str, gprMax.studies.EmbeddedFarFieldBank]
- incident_matrix
measured incident modal matrix for all cases, when retained.
- Type
Optional[NDArray[numpy.complexfloating]]
- outgoing_matrix
measured outgoing modal matrix for all cases, when retained.
- Type
Optional[NDArray[numpy.complexfloating]]
- power_wave_valid_matrix
physical power-wave validity for the measured modal matrices.
- Type
Optional[NDArray[numpy.bool]]
- coefficient_valid_wave_matrix
generalized-coefficient validity for the measured modal matrices.
- Type
Optional[NDArray[numpy.bool]]
- deembedding_condition_number
condition number of the incident-wave solve at each frequency.
- Type
Optional[NDArray[numpy.floating]]
- deembedding_valid
validity of that solve at each frequency.
- Type
Optional[NDArray[numpy.bool]]
- evaluate_array_state(state: ArrayState) ArrayStateResult
Evaluate one post-processed array state from the embedded basis.
- evaluate_codebook(codebook: ArrayCodebook) tuple[gprMax.studies.ArrayStateResult, ...]
Evaluate every named state in a validated array codebook.
- excitation_weights(excitations: Iterable[ModalWeight])
Return frequency-dependent incident power-wave weights.
- classmethod from_hdf5(filename: Union[str, Path]) EigenmodeStudyResult
Load an aggregate eigenmode study for offline array synthesis.
- outgoing(excitations: Iterable[ModalWeight])
Apply the assembled S matrix to a weighted incident-wave vector.
Zero-weight channels are omitted rather than multiplied by their stored NaNs. An output is NaN when any active input lacks a valid generalized coefficient to that output. Use
power_wave_valid_sseparately when the result must also represent propagating real-power waves.
- class gprMax.studies.ModalWeight(port: int, mode: int, power: float = 1.0, phase_deg: float = 0.0, delay_s: float = 0.0)
One modal array weight using power, phase, and/or true time delay.
- class gprMax.studies.ArrayState(id: str, drives: Iterable[ModalWeight], *, description: str = '')
A named set of modal power, phase-shifter, and true-time-delay weights.
- class gprMax.studies.ArrayCodebook(states: Iterable[ArrayState], *, embedded_far_fields: Iterable[EmbeddedFarFieldSpec] = (), description: str = '', source_path: Optional[Union[Path, str]] = None, source_text: Optional[str] = None)
Versioned modal-array states and requested embedded far-field bases.
- class gprMax.studies.EmbeddedFarFieldSpec(transform_id: str, output_id: str)
One frequency-domain far-field request retained as an embedded basis.
- class gprMax.studies.EmbeddedFarFieldBank(transform_id: str, output_id: str, frequency: NDArray[floating], theta: NDArray[floating], phi: NDArray[floating], etheta: NDArray[complexfloating], ephi: NDArray[complexfloating], sphere_theta: NDArray[floating], sphere_phi: NDArray[floating], sphere_weights: NDArray[floating], sphere_etheta: NDArray[complexfloating], sphere_ephi: NDArray[complexfloating], valid: NDArray[bool], impedance: float, theta_order: int, phi_order: int, enclosure_radius: float)
Per-unit-incident-power complex field basis ordered by modal channel.
Requested-direction fields have shape
(F, D, C)and full-sphere fields have shape(F, Q, C), whereFis frequency,Dis the number of requested directions,Qis the internal quadrature size, andCis the modal-channel count. Complex fields are range-normalized field per square-root watt of incident modal power.- transform_id
source frequency-transform identifier.
- Type
str
- output_id
source far-field request identifier.
- Type
str
- frequency
frequency axis in Hz.
- Type
NDArray[numpy.floating]
- theta
requested polar angles in degrees.
- Type
NDArray[numpy.floating]
- phi
requested azimuthal angles in degrees.
- Type
NDArray[numpy.floating]
- etheta
embedded requested-direction \(E_\theta\) fields.
- Type
NDArray[numpy.complexfloating]
- ephi
embedded requested-direction \(E_\phi\) fields.
- Type
NDArray[numpy.complexfloating]
- sphere_theta
internal full-sphere polar angles in degrees.
- Type
NDArray[numpy.floating]
- sphere_phi
internal full-sphere azimuthal angles in degrees.
- Type
NDArray[numpy.floating]
- sphere_weights
full-sphere solid-angle quadrature weights.
- Type
NDArray[numpy.floating]
- sphere_etheta
embedded full-sphere \(E_\theta\) fields.
- Type
NDArray[numpy.complexfloating]
- sphere_ephi
embedded full-sphere \(E_\phi\) fields.
- Type
NDArray[numpy.complexfloating]
- valid
physical modal-channel validity mask with shape
(F, C).- Type
NDArray[numpy.bool]
- impedance
lossless exterior wave impedance in ohms.
- Type
float
- theta_order
full-sphere polar quadrature order.
- Type
int
- phi_order
full-sphere azimuthal quadrature order.
- Type
int
- enclosure_radius
radius in metres enclosing the transformed source.
- Type
float
- class gprMax.studies.ArrayStateResult(id: str, frequency: NDArray[floating], incident: NDArray[complexfloating], outgoing: NDArray[complexfloating], active_reflection: NDArray[complexfloating], incident_power: NDArray[floating], reflected_power: NDArray[floating], accepted_power: NDArray[floating], tarc: NDArray[floating], valid: NDArray[bool], far_fields: Mapping[str, ArrayFarFieldResult])
Network and optional radiation result for one named array state.
- id
array-state identifier.
- Type
str
- frequency
frequency axis in Hz with shape
(F,).- Type
NDArray[numpy.floating]
- incident
incident modal power waves with shape
(F, C).- Type
NDArray[numpy.complexfloating]
- outgoing
outgoing modal power waves with shape
(F, C).- Type
NDArray[numpy.complexfloating]
- active_reflection
active reflection coefficient for each driven modal channel, with shape
(F, C).- Type
NDArray[numpy.complexfloating]
- incident_power
total incident power in W.
- Type
NDArray[numpy.floating]
- reflected_power
total reflected power in W.
- Type
NDArray[numpy.floating]
- accepted_power
net accepted power in W.
- Type
NDArray[numpy.floating]
- tarc
total active reflection coefficient.
- Type
NDArray[numpy.floating]
- valid
frequency-bin network validity mask.
- Type
NDArray[numpy.bool]
- far_fields
mapping from
transform_id/output_idto synthesizedArrayFarFieldResultobjects.- Type
Mapping[str, gprMax.studies.ArrayFarFieldResult]
- class gprMax.studies.ArrayFarFieldResult(transform_id: str, output_id: str, theta: NDArray[floating], phi: NDArray[floating], etheta: NDArray[complexfloating], ephi: NDArray[complexfloating], radiation_intensity: NDArray[floating], radiated_power: NDArray[floating], directivity: NDArray[floating], directivity_dbi: NDArray[floating], gain: NDArray[floating], gain_dbi: NDArray[floating], realized_gain: NDArray[floating], realized_gain_dbi: NDArray[floating], radiation_efficiency: NDArray[floating], total_efficiency: NDArray[floating], maximum_directivity: NDArray[floating], maximum_directivity_dbi: NDArray[floating], maximum_theta: NDArray[floating], maximum_phi: NDArray[floating], valid: NDArray[bool])
Coherently synthesized fields and radiation metrics for one array state.
Direction-dependent arrays have shape
(F, D); integrated, maximum, efficiency, and validity arrays have shape(F,).- transform_id
source frequency-transform identifier.
- Type
str
- output_id
source far-field request identifier.
- Type
str
- theta
requested polar angles in degrees.
- Type
NDArray[numpy.floating]
- phi
requested azimuthal angles in degrees.
- Type
NDArray[numpy.floating]
- etheta
coherently combined range-normalized \(E_\theta\).
- Type
NDArray[numpy.complexfloating]
- ephi
coherently combined range-normalized \(E_\phi\).
- Type
NDArray[numpy.complexfloating]
- radiation_intensity
radiation intensity in W/sr.
- Type
NDArray[numpy.floating]
- radiated_power
full-sphere integrated radiated power in W.
- Type
NDArray[numpy.floating]
- directivity
linear directivity.
- Type
NDArray[numpy.floating]
- directivity_dbi
directivity in dBi.
- Type
NDArray[numpy.floating]
- gain
linear accepted-power gain.
- Type
NDArray[numpy.floating]
- gain_dbi
accepted-power gain in dBi.
- Type
NDArray[numpy.floating]
- realized_gain
linear incident-power gain.
- Type
NDArray[numpy.floating]
- realized_gain_dbi
incident-power gain in dBi.
- Type
NDArray[numpy.floating]
- radiation_efficiency
radiated power divided by accepted power.
- Type
NDArray[numpy.floating]
- total_efficiency
radiated power divided by incident power.
- Type
NDArray[numpy.floating]
- maximum_directivity
maximum linear directivity.
- Type
NDArray[numpy.floating]
- maximum_directivity_dbi
maximum directivity in dBi.
- Type
NDArray[numpy.floating]
- maximum_theta
polar angle of maximum directivity in degrees.
- Type
NDArray[numpy.floating]
- maximum_phi
azimuthal angle of maximum directivity in degrees.
- Type
NDArray[numpy.floating]
- valid
frequency-bin validity mask.
- Type
NDArray[numpy.bool]
- gprMax.studies.modal_array_weights(frequency, channel_ports, channel_modes, excitations: Iterable[ModalWeight])
Build incident modal power waves using the engineering FFT convention.
A constant phase shifter contributes
exp(+j phase). A true time delay contributesexp(-j 2 pi f delay). The coefficient magnitude is the square root of the requested incident power in watts.
- gprMax.studies.combine_embedded_modal_responses(responses, weights, *, channel_axis=-1)
Linearly combine complex embedded responses with modal weights.
responsesmust have frequency as its first axis and one axis ordered like the study’s modal channels. All intervening axes (observation point, angle, field component, and so on) are retained.
Plane-wave and RCS studies
PlaneWaveStudy schedules incident directions and polarisation. GPRStudy schedules point-source acquisitions.
- class gprMax.studies.PlaneWaveStudy(cases: Sequence[StudyCase], *, source_path: Optional[Union[Path, str]] = None, source_text: Optional[str] = None)
Reusable-geometry study with one rebuilt discrete plane wave per case.
The main Yee geometry is retained, but the auxiliary one-dimensional DPW grid is deliberately reconstructed because its integer direction mapping, length, projections, material profile, and PML state depend on the case. Declarative NTFF monitors are reconstructed with it so their accumulated DFT and incident-wave normalisation state cannot leak between cases.
- class gprMax.studies.StudyCase(id: str, states: Iterable[ObjectState])
A named set of object overrides.
- class gprMax.studies.ObjectState(object: Any, **parameters: Any)
Overrides for one study object in one case.
objectmay be a deterministic object ID such as"hertzian_dipole_1"/"rx_1"or the corresponding Python API user-object instance.
Other general settings
Typical general settings are added directly to the scene:
scene.add(gprMax.Title(name='buried_target'))
scene.add(gprMax.OMPThreads(n=8))
scene.add(gprMax.TimeStepStabilityFactor(f=0.95))
scene.add(gprMax.OutputDir(dir='results'))
scene.add(gprMax.MagneticAveraging(mode='harmonic'))
scene.add(gprMax.DispersiveAveraging(enabled=True))
Material functions
Material
- class gprMax.user_objects.cmds_multiuse.Material(**kwargs)
- Specifies a material in the model described by a set of constitutive
parameters.
- er
float required for the relative electric permittivity.
- se
float required for the electric conductivity (Siemens/metre).
- mr
float required for the relative magnetic permeability.
- sm
float required for the magnetic loss.
- id
string used as identifier for material. ‘+’ is reserved for internally generated material IDs; use ‘_’ in user-defined IDs.
User-defined material IDs must not contain +. It is reserved for averaged
and other internally generated materials; use _ instead. This also applies
to the optional id of gprMax.MaterialFromDatabase. Generated names
stored by gprMax.GeometryObjectsWrite remain valid when restored with
gprMax.GeometryObjectsRead.
Surface impedance
- class gprMax.user_objects.cmds_multiuse.SurfaceImpedance(id: str, resistance: Optional[float] = None, *, preset: Optional[str] = None, conductivity: Optional[float] = None, fit_frequency_range: Optional[Tuple[float, float]] = None, fit_order: Union[str, int] = 'auto', fit_tolerance: float = 0.002, plot_fit: bool = False)
Define a reusable scalar passive surface impedance.
Assign its
iddirectly as thematerial_idof a closed, cell-occupying geometry object. Sheet, edge, zero-thickness, and directionalmaterial_idsassignments are unsupported.Select exactly one of a constant
resistance, a named bulk-metalpreset, or a user-supplied bulk-metalconductivity. Fitted models requirefit_frequency_range=(fmin, fmax)and are converted internally to a passive Foster realization.fit_order='auto'tests increasing actual runtime pole counts and chooses the first deterministic local fit independently certified to reachfit_tolerance. An integer asks for exactly that many Foster poles. The constant-resistance form is an idealised broadband boundary rather than a complete physical material model and emits a warning when built.resistance=float('inf')selects the exact voxel-face PMC limit with zero tangential surface admittance. Passive impedance walls can continue uniformly along a PML absorption direction. Domain and CPU virtual-guide PML support heterogeneous isotropic retained hosts, including loss and electric dispersion, with each constituent uniformly extruded through the slab. Virtual apertures advance independent bulk polarization and surface-current histories with the coupled electric field.
Argument |
Default |
Meaning and constraints |
|---|---|---|
|
Required |
Unique material identifier used by geometry. Shares the bulk-material namespace; do not use |
|
None |
Named thick-metal model. Choose exactly one of |
|
None |
Positive finite bulk conductivity in S/m, fitted to a good-conductor surface response. This is not a resistance in ohms. |
|
None |
Positive surface resistance in ohms, or positive infinity for exact voxel-face PMC. Zero, negative values, NaN, and negative infinity are invalid; use PEC for a zero-impedance wall. |
|
Required for a fit |
Positive finite increasing |
|
|
Select the smallest runtime pole count from 1 through 64 meeting the tolerance. An integer from 1 through 64 requests that exact count; if the tolerance is not met, gprMax issues a warning rather than changing the count. |
|
|
Positive finite relative impedance-fit tolerance (0.2% by default). Automatic fitting must meet it; explicit-order fitting issues a warning if it is not met. |
|
|
Write a fit PNG in geometry-only runs. |
Assign the ID to a closed, cell-occupying geometry object. For model choices, fit-band selection, geometry, and supported configurations, see Surface impedance and impedance volumes. The boundary equations are in Surface impedance: theory and validation; stored metadata is in Surface-impedance reproducibility metadata.
Material from database
- class gprMax.user_objects.cmds_multiuse.MaterialFromDatabase(**kwargs)
Create a material from a versioned JSON material database.
Official databases are installed with gprMax. A user database is a JSON file named
<database>.jsonbeside the input file, or in the current working directory for a direct Python API model.- database
official or local database name.
- material
material entry key in the database.
- id
optional local material ID; defaults to
material. This can provide a model-specific name, avoid a collision, or match the material name expected by imported geometry. ‘+’ is reserved for internally generated material IDs.
See Material databases for database lookup, schema, provenance, and geometry-file migration.
Material mass density
- class gprMax.user_objects.cmds_multiuse.MaterialDensity(*, density, material_ids)
Assign a physical mass density to one or more existing materials.
Density is cell-centred metadata used by derived quantities such as SAR; it does not alter electromagnetic update coefficients or material averaging.
- density
Finite mass density greater than zero in kg/m3.
- material_ids
Material identifiers to which the density is assigned.
Mass density is optional cell-centred physical metadata in SI units (\(\mathrm{kg\,m^{-3}}\)). It does not alter electromagnetic update coefficients or dielectric smoothing. Derived dosimetry outputs require a finite, positive density for every selected material.
Material range
- class gprMax.user_objects.cmds_multiuse.MaterialRange(**kwargs)
Creates varying material properties for stochastic models.
- er_lower
float required for lower relative permittivity value.
- er_upper
float required for upper relative permittivity value.
- sigma_lower
float required for lower conductivity value.
- sigma_upper
float required for upper conductivity value.
- mr_lower
float required for lower relative magnetic permeability value.
- mr_upper
float required for upper relative magnetic permeability value.
- ro_lower
float required for lower magnetic loss value.
- ro_upper
float required for upper magnetic loss value.
- id
string used as identifier for this variable material.
MaterialRange defines bounded stochastic constitutive properties for a
gprMax.FractalBox; it does not create a homogeneous material. See
#material_range for how the sampled values are used.
Material list
- class gprMax.user_objects.cmds_multiuse.MaterialList(**kwargs)
Creates varying material properties for stochastic models.
- list_of_materials
list of material IDs
- id
string used as identifier for this variable material.
MaterialList groups existing material IDs for stochastic assignment by a
gprMax.FractalBox. See #material_list for the
corresponding input-file command.
Debye Dispersion
- class gprMax.user_objects.cmds_multiuse.AddDebyeDispersion(**kwargs)
Adds dispersive properties to already defined Material based on a multi-pole Debye formulation.
Perfect electric and magnetic conductors cannot be assigned electric dispersion, including custom materials with infinite electric or magnetic conductivity.
- poles
float required for number of Debye poles.
- er_delta
tuple required for difference between zero-frequency relative permittivity and relative permittivity at infinite frequency for each pole.
- tau
tuple required for relaxation time (secs) for each pole.
- material_ids
list required of material ids to apply dispersive properties.
Lorentz Dispersion
- class gprMax.user_objects.cmds_multiuse.AddLorentzDispersion(**kwargs)
Adds dispersive properties to already defined Material based on a multi-pole Lorentz formulation.
Perfect electric and magnetic conductors cannot be assigned electric dispersion, including custom materials with infinite electric or magnetic conductivity.
- poles
float required for number of Lorentz poles.
- er_delta
tuple required for difference between zero-frequency relative permittivity and relative permittivity at infinite frequency for each pole.
- omega
tuple required for resonance frequency (Hz) for each pole.
- delta
tuple required for damping coefficient (per second) for each pole.
- material_ids
list required of material ids to apply dispersive properties.
Drude Dispersion
- class gprMax.user_objects.cmds_multiuse.AddDrudeDispersion(**kwargs)
Adds dispersive properties to already defined Material based on a multi-pole Drude formulation.
Perfect electric and magnetic conductors cannot be assigned electric dispersion, including custom materials with infinite electric or magnetic conductivity.
- poles
float required for number of Drude poles.
- omega
tuple required for plasma frequency (Hz) for each pole.
- alpha
tuple required for inverse of relaxation time (per second) for each pole.
- material_ids
list required of material ids to apply dispersive properties.
Material CRIM
- class gprMax.user_objects.cmds_multiuse.MaterialCrim(**kwargs)
Mixing model based on the Complex Refractive Index Model (CRIM), combining a fixed-fraction non-dispersive matrix material with a single-pole Debye dispersive material (e.g. water or brine); the remaining volume fraction is assumed to be air.
- matrix_id
string for ID of an existing non-dispersive material used for the fixed-fraction matrix (solid) phase.
- matrix_fraction
float required for fixed volumetric fraction of the matrix phase.
- dispersive_id
string for ID of an existing single-pole Debye material used for the dispersive phase.
- fraction_lower
float required for lower boundary of the volumetric fraction of the dispersive phase.
- fraction_upper
float required for upper boundary of the volumetric fraction of the dispersive phase.
- f_min
float required for lower bound of the frequency range (Hz) used to fit the CRIM mixing curve.
- f_max
float required for upper bound of the frequency range (Hz) used to fit the CRIM mixing curve.
- a
float required for the CRIM shape factor.
- id
string used as identifier for this CRIM mixing model.
See #material_crim for the CRIM mixing formula and how it is specialised to the matrix/dispersive-phase/air case used here.
The CRIM object, like the Peplinski object below, is a mixing model for a
FractalBox, rather than a homogeneous material. It combines a
fixed-fraction non-dispersive matrix material with a single-pole Debye
dispersive material (assumed water or brine); the remaining volume fraction
is assumed to be air. Both materials must already exist in the scene, and
the dispersive material must have exactly one Debye pole. Conductivity is
mixed separately by volume fraction as described for the hash command:
scene.add(gprMax.Material(er=5, se=0, mr=1, sm=0, id='sand'))
scene.add(gprMax.Material(er=4.9, se=0, mr=1, sm=0, id='water'))
scene.add(gprMax.AddDebyeDispersion(
poles=1, er_delta=(73.3389,), tau=(8.0994e-12,),
material_ids=('water',),
))
scene.add(gprMax.MaterialCrim(
matrix_id='sand', matrix_fraction=0.6,
dispersive_id='water', fraction_lower=0.02, fraction_upper=0.35,
f_min=1e6, f_max=3e9, a=0.5,
id='wetsand',
))
scene.add(gprMax.FractalBox(
p1=(0, 0, 0), p2=(0.1, 0.1, 0.08),
frac_dim=1.5, weighting=(1, 1, 1),
n_materials=10, mixing_model_id='wetsand',
id='my_fractal_box',
))
Soil Peplinski
- class gprMax.user_objects.cmds_multiuse.SoilPeplinski(**kwargs)
- Mixing model for soils proposed by Peplinski et al.
- sand_fraction
float required for sand fraction of soil.
- clay_fraction
float required for clay of soil.
- bulk_density
float required for bulk density of soil (gm/cm^3).
- sand_density
float required for density of sand particles in soil (gm/cm^3).
- water_fraction_lower
float required for lower boundary of volumetric water fraction of the soil.
- water_fraction_upper
float required for upper boundary of volumetric water fraction of the soil.
- id
string used as identifier for soil.
The dispersion objects modify materials that have already been added to the same scene. Each material ID below is therefore unique. These objects describe electric dispersion and cannot target PEC or PMC materials, including custom materials with infinite electric or magnetic conductivity:
scene.add(gprMax.Material(
er=6, se=0.01, mr=1, sm=0, id='half_space'
))
scene.add(gprMax.Material(
er=4, se=0, mr=1, sm=0, id='debye_medium'
))
scene.add(gprMax.AddDebyeDispersion(
poles=1, er_delta=(2.0,), tau=(1e-10,),
material_ids=('debye_medium',),
))
scene.add(gprMax.Material(
er=3, se=0, mr=1, sm=0, id='lorentz_medium'
))
scene.add(gprMax.AddLorentzDispersion(
poles=1, er_delta=(2.0,), omega=(2e10,), delta=(5e9,),
material_ids=('lorentz_medium',),
))
scene.add(gprMax.Material(
er=1, se=0, mr=1, sm=0, id='drude_medium'
))
scene.add(gprMax.AddDrudeDispersion(
poles=1, omega=(2e10,), alpha=(5e9,),
material_ids=('drude_medium',),
))
The Peplinski object is a mixing model for a FractalBox, rather than
a homogeneous material:
scene.add(gprMax.SoilPeplinski(
sand_fraction=0.5, clay_fraction=0.2,
bulk_density=2.0, sand_density=2.66,
water_fraction_lower=0.05, water_fraction_upper=0.25,
id='soil_mix',
))
Object construction functions
Object construction commands are processed in the order they appear in the scene. Therefore space in the model allocated to a specific material using for example the gprMax.user_objects.cmds_geometry.box.Box command can be reallocated to another material using the same or any other object construction command. Space in the model can be regarded as a canvas in which objects are introduced and one can be overlaid on top of the other overwriting its properties in order to produce the desired geometry. The object construction commands can therefore be used to create complex shapes and configurations.
Closed impedance volumes
Assign a gprMax.SurfaceImpedance ID directly as the material_id
of a supported ordinary geometry object. No separate conversion object is
needed. SurfaceImpedance defines the boundary response; assigning its ID
to geometry creates an opaque impedance volume. Interior fields are excluded,
not solved using a bulk conductivity. Even a one-cell-thick volume is opaque,
not a transmissive sheet.
scene.add(gprMax.SurfaceImpedance(
id='metal',
preset='copper',
fit_frequency_range=(8e9, 12e9),
))
scene.add(gprMax.Sphere(
p1=(0.15, 0.10, 0.08), r=0.025,
material_id='metal', averaging='n',
))
Use a scalar material_id and finite-volume geometry that occupies mesh cells. Sheets,
lines, directional assignments, and dielectric smoothing are unavailable
for this one-sided opaque boundary. Geometry follows declaration order:
later objects overwrite earlier ones. The final voxel topology is checked after all cutouts.
Tags remain optional metadata.
For supported primitives, PEC/PMC contacts, symmetry, 2D extrusion, clearance, and import/export limitations, see Surface impedance and impedance volumes. Uniform propagation through PML and virtual-guide apertures has additional host-material and coverage requirements in Waveguides and absorbers. Infinite surface resistance gives exact voxel-face PMC; built-in PMC volume geometry retains its legacy reflection-plane limitation.
The compiled boundary uses the same discrete surface response in FDTD and modal solves. The bulk modal operator uses Yee temporal and longitudinal difference symbols, while bulk dispersive poles still use their analytic physical-frequency response. See Surface impedance: theory and validation for the boundary reduction and Eigenmode ports: theory and numerical methods for modal operators.
Box
- class gprMax.user_objects.cmds_geometry.box.Box(**kwargs)
- Introduces an orthogonal parallelepiped with specific properties into
the model.
- p1
list of the lower left (x,y,z) coordinates of the parallelepiped.
- p2
list of the upper right (x,y,z) coordinates of the parallelepiped.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to occupied cells.
Cone
- class gprMax.user_objects.cmds_geometry.cone.Cone(**kwargs)
- Introduces a circular cone into the model. The difference with the cylinder is that the faces of the cone
can have different radii and one of them can be zero.
- p1
list of the coordinates (x,y,z) of the centre of the first face of the cone.
- p2
list of the coordinates (x,y,z) of the centre of the second face of the cone.
- r1
float of the radius of the first face of the cone.
- r2
float of the radius of the second face of the cone.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to occupied cells.
Cylinder
- class gprMax.user_objects.cmds_geometry.cylinder.Cylinder(**kwargs)
Introduces a circular cylinder into the model.
- p1
list of the coordinates (x,y,z) of the centre of the first face of the cylinder.
- p2
list of the coordinates (x,y,z) of the centre of the second face of the cylinder.
- r
float of the radius of the cylinder.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to occupied cells.
Cylindrical Sector
- class gprMax.user_objects.cmds_geometry.cylindrical_sector.CylindricalSector(**kwargs)
Introduces a cylindrical sector (shaped like a slice of pie) into the model.
- normal
string for the direction of the axis of the cylinder from which the sector is defined and can be x, y, or z.
- ctr1
float for the first coordinate of the centre of the cylindrical sector.
- ctr2
float for the second coordinate of the centre of the cylindrical sector.
- extent1
float for the first thickness from the centre of the cylindrical sector.
- extent2
float for the second thickness from the centre of the cylindrical sector.
- r
float for the radius of the cylindrical sector.
- start
float for the starting angle (in degrees) for the cylindrical sector.
- end
float for the angle (in degrees) swept by the cylindrical sector.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to occupied cells.
Edge
- class gprMax.user_objects.cmds_geometry.edge.Edge(**kwargs)
Introduces a wire with specific properties into the model.
- p1
list of the coordinates (x,y,z) of the starting point of the edge.
- p2
list of the coordinates (x,y,z) of the ending point of the edge.
- material_id
string for the material identifier that must correspond to material that has already been defined.
Thin Wire
- class gprMax.user_objects.cmds_geometry.thin_wire.ThinWire(**kwargs)
Introduces an axis-aligned PEC thin wire with physical radius
a.The logarithmic radius factor follows Umashankar, Taflove, and Beker (IEEE TAP, 1987, doi:10.1109/TAP.1987.1144000). The surrounding magnetic updates use the improved projected-field factors of Mäkinen, Juntunen, and Kivikoski (IEEE T-MTT, 2002). The charge-based open-end correction from the latter paper is not implemented.
- Parameters
p1 – Coordinates of the start of the wire.
p2 – Coordinates of the end of the wire.
radius – Physical wire radius in metres.
scene.add(gprMax.ThinWire(
p1=(0.10, 0.10, 0.02),
p2=(0.10, 0.10, 0.12),
radius=0.0001,
))
Magnetic Edge
- class gprMax.user_objects.cmds_geometry.magnetic_edge.MagneticEdge(**kwargs)
- Introduces a single magnetic (H) edge with specific properties into
the model - the magnetic dual of #edge.
- p1
list of the coordinates (x,y,z) of the starting point of the edge.
- p2
list of the coordinates (x,y,z) of the ending point of the edge.
- material_id
string for the material identifier that must correspond to material that has already been defined.
scene.add(gprMax.MagneticEdge(
p1=(0.5, 0.5, 0.5),
p2=(0.7, 0.5, 0.5),
material_id='pmc',
))
Ellipsoid
- class gprMax.user_objects.cmds_geometry.ellipsoid.Ellipsoid(**kwargs)
Introduces an ellipsoidal object with specific parameters into the model.
- p1
list of the coordinates (x,y,z) of the centre of the ellipsoid.
- xr
float for x-semiaxis of the ellipsoid.
- yr
float for y-semiaxis of the ellipsoid.
- zr
float for z-semiaxis of the ellipsoid.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to occupied cells.
Plate
- class gprMax.user_objects.cmds_geometry.plate.Plate(**kwargs)
Introduces a plate with specific properties into the model.
- p1
list of the lower left (x,y,z) coordinates of the plate.
- p2
list of the upper right (x,y,z) coordinates of the plate.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
two material identifiers for the plate’s tangential directions: y/z for a yz-plane plate, x/z for an xz-plane plate, or x/y for an xy-plane plate.
Sphere
- class gprMax.user_objects.cmds_geometry.sphere.Sphere(**kwargs)
Introduces a spherical object with specific parameters into the model.
- p1
list of the coordinates (x,y,z) of the centre of the sphere.
- r
float of radius of the sphere.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to occupied cells.
Triangle
- class gprMax.user_objects.cmds_geometry.triangle.Triangle(**kwargs)
- Introduces a triangular patch or a triangular prism with specific
properties into the model.
- p1
list of the coordinates (x,y,z) of the first apex of the triangle.
- p2
list of the coordinates (x,y,z) of the second apex of the triangle.
- p3
list of the coordinates (x,y,z) of the third apex of the triangle.
- thickness
float for the thickness of the triangular prism. If the thickness is zero then a triangular patch is created.
- material_id
string for the material identifier that must correspond to material that has already been defined.
- material_ids
list of material identifiers in the x, y, z directions.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string for a volumetric triangular prism. It is not accepted when
thicknessis zero.
The following compact examples show the required geometry keywords. The
referenced material IDs must already exist; pec and pmc are built in.
scene.add(gprMax.Box(
p1=(0, 0, 0), p2=(0.30, 0.20, 0.08), material_id='half_space'
))
scene.add(gprMax.Cone(
p1=(0.05, 0.05, 0.08), p2=(0.05, 0.05, 0.13),
r1=0.02, r2=0, material_id='pec',
))
scene.add(gprMax.Cylinder(
p1=(0.15, 0.02, 0.05), p2=(0.15, 0.18, 0.05),
r=0.01, material_id='pec',
))
scene.add(gprMax.CylindricalSector(
normal='z', ctr1=0.15, ctr2=0.10,
extent1=0.04, extent2=0.08, r=0.04,
start=0, end=90, material_id='half_space',
))
scene.add(gprMax.Edge(
p1=(0.10, 0.10, 0.02), p2=(0.10, 0.10, 0.12),
material_id='pec',
))
scene.add(gprMax.ThinWire(
p1=(0.12, 0.10, 0.02), p2=(0.12, 0.10, 0.12),
radius=0.0001,
))
scene.add(gprMax.Ellipsoid(
p1=(0.20, 0.10, 0.08), xr=0.03, yr=0.02, zr=0.01,
material_id='half_space',
))
scene.add(gprMax.Plate(
p1=(0.04, 0.04, 0.06), p2=(0.10, 0.10, 0.06),
material_id='pec',
))
scene.add(gprMax.Sphere(
p1=(0.24, 0.10, 0.08), r=0.015, material_id='pec'
))
scene.add(gprMax.Triangle(
p1=(0.04, 0.04, 0.04), p2=(0.10, 0.04, 0.04),
p3=(0.04, 0.10, 0.04), thickness=0.01,
material_id='half_space',
))
Fractal Box
- class gprMax.user_objects.cmds_geometry.fractal_box.FractalBox(**kwargs)
- Introduces an orthogonal parallelepiped with fractal distributed
properties which are related to a mixing model or normal material into the model.
- p1
list of the lower left (x,y,z) coordinates of the parallelepiped.
- p2
list of the upper right (x,y,z) coordinates of the parallelepiped.
- frac_dim
float for the fractal dimension which, for an orthogonal parallelepiped, should take values between zero and three.
- weighting
list of the weightings in the x, y, z direction of the parallelepiped.
- n_materials
int of the number of materials to use for the fractal distribution (defined according to the associated mixing model). This should be set to one if using a normal material instead of a mixing model.
- mixing_model_id
string identifier for the associated mixing model or material. Several boxes may share a mixing model; each box uses its own n_materials bin mapping.
- id
string identifier for the fractal box itself.
- seed
(optional) float parameter which controls the seeding of the random number generator used to create the fractals.
- averaging
string (y or n) used to switch on and off dielectric smoothing.
- tag
optional semantic geometry-tag string written to the final cells occupied by the fractal volume.
Fractal definitions can be reused for a geometry preview followed by a solve,
or in multiple rebuilt Scenes. Each fresh grid gets its own fractal volume and
material-bin mapping. Supply a seed for reproducible geometry. With
geometry_fixed=True, the already-built geometry is retained instead.
Note
We are not aware of a formulation of Perfectly Matched Layer (PML) absorbing boundary that can specifically handle distributions of material properties (such as those created by fractals) throughout the thickness of the PML, i.e. this is a required area of research. Our PML formulations can work to an extent depending on your modelling scenario and requirements. You may need to increase the thickness of the PML and/or consider tuning the parameters of the PML (PML functions) to improve performance for your specific model.
Add Grass
- class gprMax.user_objects.cmds_geometry.add_grass.AddGrass(**kwargs)
Adds grass with roots to a FractalBox class in the model.
- p1
list of the lower left (x,y,z) coordinates of a surface on a FractalBox class.
- p2
list of the upper right (x,y,z) coordinates of a surface on a FractalBox class.
- frac_dim
float for the fractal dimension which, for an orthogonal parallelepiped, should take values between zero and three.
- limits
list to define lower and upper limits for a range over which the height of the blades of grass can vary.
- n_blades
int for the number of blades of grass that should be applied to the surface area.
- fractal_box_id
string identifier for the FractalBox class that the grass should be applied to.
- seed
optional integer used to seed the random number generator. If omitted, a different distribution is generated on each run.
Add Surface Roughness
- class gprMax.user_objects.cmds_geometry.add_surface_roughness.AddSurfaceRoughness(**kwargs)
Adds surface roughness to a FractalBox class in the model.
- p1
list of the lower left (x,y,z) coordinates of a surface on a FractalBox class.
- p2
list of the upper right (x,y,z) coordinates of a surface on a FractalBox class.
- frac_dim
float for the fractal dimension which, for an orthogonal parallelepiped, should take values between zero and three.
- weighting
list with weightings in the first and second direction of the surface.
- limits
list to define lower and upper limits for a range over which the surface roughness can vary.
- fractal_box_id
string identifier for the FractalBox class that the surface roughness should be applied to.
- seed
(optional) float parameter which controls the seeding of the random number generator used to create the fractals.
Add Surface Water
- class gprMax.user_objects.cmds_geometry.add_surface_water.AddSurfaceWater(**kwargs)
Adds surface water to a FractalBox class in the model.
- p1
list of the lower left (x,y,z) coordinates of a surface on a FractalBox class.
- p2
list of the upper right (x,y,z) coordinates of a surface on a FractalBox class.
- depth
float that defines the depth of the water, which should be specified relative to the dimensions of the #fractal_box that the surface water is being applied.
- fractal_box_id
string identifier for the FractalBox class that the surface water should be applied to.
A fractal volume can use either a normal material or a mixing model such as
soil_mix from the material example above. Surface modifiers refer to the
fractal box by its ID and must be added after it:
scene.add(gprMax.FractalBox(
p1=(0, 0, 0), p2=(0.30, 0.20, 0.10),
frac_dim=1.5, weighting=(1, 1, 1), n_materials=20,
mixing_model_id='soil_mix', id='ground', seed=1, tag='soil_layer_1',
))
scene.add(gprMax.AddSurfaceRoughness(
p1=(0, 0, 0.10), p2=(0.30, 0.20, 0.10),
frac_dim=1.5, weighting=(1, 1), limits=(0.08, 0.12),
fractal_box_id='ground', seed=1,
))
scene.add(gprMax.AddSurfaceWater(
p1=(0, 0, 0.10), p2=(0.30, 0.20, 0.10),
depth=0.105, fractal_box_id='ground',
))
scene.add(gprMax.AddGrass(
p1=(0, 0, 0.10), p2=(0.30, 0.20, 0.10),
frac_dim=1.5, limits=(0.01, 0.03), n_blades=100,
fractal_box_id='ground', seed=1,
))
Geometry View
- class gprMax.user_objects.cmds_output.GeometryView(p1: Tuple[float, float, float], p2: Tuple[float, float, float], dl: Tuple[float, float, float], output_type: str, filename: str)
Outputs to file(s) information about the geometry (mesh) of model.
The geometry information is saved in Visual Toolkit (VTK) formats.
- p1
tuple required for lower left (x,y,z) coordinates of volume of geometry view in metres.
- p2
tuple required for upper right (x,y,z) coordinates of volume of geometry view in metres.
- dl
tuple required for spatial discretisation of geometry view in metres.
- output_type
string required for per-cell ‘n’ (normal) or per-cell-edge ‘f’ (fine) geometry views.
- filename
string required for filename where geometry view will be stored in the same directory as input file.
Geometry Objects Read
- class gprMax.user_objects.cmds_geometry.geometry_objects_read.GeometryObjectsRead(**kwargs)
Allows you to insert pre-defined geometry into a model.
The geometry is specified using integer arrays in an HDF5 file. These files contain
/material_keyswhich map their compact integer indices to a versioned JSON material database. Convert legacy HDF5/text pairs first withpython -m gprMax.toolboxes.MaterialDatabase convert-geometry.- p1
list of lower left (x,y,z) coordinates in the domain where the lower left corner of the geometry array should be placed.
- geofile
string path to and filename of the HDF5 file that contains an integer array which defines the geometry.
- material_database
database name, without
.json, for a keyed geometry file. The JSON file must be beside the HDF5 file.
- averaging
optional
"y"/"n"flag controlling interface averaging when a voxel-only file is reconstructed. The default is"n". Files containing complete/ID,/rigidE, and/rigidHarrays are authoritative and ignore this option.
The matfile argument is no longer supported. To reuse an old HDF5 geometry
with text material commands, follow Migrating legacy geometry and text materials, then
use geofile="geometry_converted.h5", material_database="geometry_materials".
The insertion coordinates and averaging option remain unchanged.
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.
Geometry Objects Write
- class gprMax.user_objects.cmds_output.GeometryObjectsWrite(p1: Tuple[float, float, float], p2: Tuple[float, float, float], filename: str)
- Writes geometry generated in a model to file which can be imported into
other models.
- p1
tuple required for lower left (x,y,z) coordinates of volume of output in metres.
- p2
tuple required for upper right (x,y,z) coordinates of volume of output in metres.
- filename
string required for filename where output will be stored in the same directory as input file.
Geometry views are visualisations. Geometry-object files instead preserve material-index geometry for insertion into another model. If semantic tags exist, both outputs also preserve their cell IDs and the ID-to-name table. This permits a costly tagged anatomy or geological model to be written once and inserted into later simulations without rebuilding it:
scene.add(gprMax.GeometryView(
p1=(0, 0, 0), p2=(0.30, 0.20, 0.15),
dl=(0.002, 0.002, 0.002),
filename='model_geometry', output_type='n',
))
scene.add(gprMax.GeometryObjectsWrite(
p1=(0, 0, 0), p2=(0.30, 0.20, 0.15),
filename='reusable_geometry',
))
A geometry view can be added to an HSG subgrid. Its points and VTK origin are
written in the global model coordinate system, even though its material data
are sampled from the fine local grid. GeometryObjectsWrite remains a
main-grid operation.
In a different scene, the saved geometry can be inserted at a chosen origin:
scene.add(gprMax.GeometryObjectsRead(
p1=(0.05, 0.05, 0),
geofile='reusable_geometry.h5',
material_database='reusable_geometry_materials',
averaging='y',
))
averaging='y' reconstructs a voxel-only file with dielectric interface
averaging; its backward-compatible default is 'n'. If the file contains
complete /ID, /rigidE, and /rigidH arrays, those Yee-component
arrays are authoritative and the option is ignored. Dispersive tissue
interfaces additionally require gprMax.DispersiveAveraging(enabled=True).
Material density and cell-centred geometry tags remain discrete per cell.
Source and output functions
Point-source positions and boundary components
After coordinates are rounded to grid indices, a Hertzian dipole, voltage
source, or transmission line must lie on a physical electric component;
a magnetic dipole must lie on a physical magnetic component. For a grid
with nx, ny, and nz cells, the inclusive index ranges are:
Component |
x index |
y index |
z index |
|---|---|---|---|
Ex |
0 .. nx-1 |
0 .. ny |
0 .. nz |
Ey |
0 .. nx |
0 .. ny-1 |
0 .. nz |
Ez |
0 .. nx |
0 .. ny |
0 .. nz-1 |
Hx |
0 .. nx |
0 .. ny-1 |
0 .. nz-1 |
Hy |
0 .. nx-1 |
0 .. ny |
0 .. nz-1 |
Hz |
0 .. nx-1 |
0 .. ny-1 |
0 .. nz |
For example, Ex[i,j,k] is located at
((i+0.5)*dx, j*dy, k*dz). Its last physical x index is nx-1,
although the field array also contains a padded entry at nx. By
contrast, its transverse terminal indices j=ny and k=nz remain
valid. The boundary condition still determines which components can be
excited there; the bounds check does not change PEC or PMC enforcement.
The checks also apply to dipole positions reached through SrcSteps or
a study. In 2D, sources must remain on the active invariant layer (index
0 for TM, index 1 for TE). MPI checks use the global physical grid, not
the edge of an individual rank. Subgrid checks use the translated local
fine-grid indices. Receiver and extended-source bounds are separate.
Sources sharing a field component
Hertzian dipoles or magnetic dipoles assigned to the same discretised Yee component add their contributions in source-list order. This also applies when different physical coordinates round to the same component. Different polarisations address different component arrays.
CPU and accelerator solvers use the same conventional-source ordering: voltage sources, then transmission lines, then Hertzian dipoles for the electric update; magnetic dipoles precede magnetic frills for the magnetic update. Within each family, input order is preserved. The accelerator kernels process ordinary source lists and transmission-line electric updates sequentially, so coincident writes do not race.
Not every source adds to the field. An active hard voltage source or transmission line assigns its electric component; a later assignment to that component takes precedence. This reproduces the CPU update rules, not a combined circuit model of several feeds sharing one terminal. Existing restrictions on overlapping magnetic-frill stencils and duplicate network-terminal edges still apply.
Waveform
- class gprMax.user_objects.cmds_multiuse.Waveform(**kwargs)
Create waveform to use with sources in the model.
- wave_type
Waveform type. One of ‘gaussian’, ‘gauspulse’, ‘gaussiandot’, ‘gaussiandotnorm’, ‘gaussiandotdot’, ‘gaussiandotdotnorm’, ‘ricker’, ‘gaussianprime’, ‘gaussiandoubleprime’, ‘sine’, ‘contsine’, ‘impulse’, or ‘user’. The continuous sine ramps over four cycles. An impulse is one nonzero sample on the source’s update lattice, not a unit-area continuous-time delta; its required positive frequency is unused. The Gaussian-modulated cosine ‘gauspulse’ uses fractional bandwidth 0.5 at -6 dB, matching MATLAB gauspuls defaults, and is delayed to start at the -60 dB envelope level. See gauspulse (modulated Gaussian).
- Type
str
- amp
Factor to scale the maximum amplitude of the waveform by. (For a #hertzian_dipole the units will be Amps, for a #voltage_source or #transmission_line the units will be Volts).
- Type
float
- freq
Centre frequency (Hz) of the waveform. In the case of the Gaussian waveform it is related to the pulse width.
- id
Identifier of the waveform.
- Type
str
- user_values
Optional 1D array of amplitude values to use with user waveform.
- user_time
Optional 1D array of time values to use with user waveform.
- kind
Optional string or int, see scipy.interpolate.interp1d - https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html#scipy-interpolate-interp1d
- Type
int | str | None
- fill_value
Optional array or ‘extrapolate’, see scipy.interpolate.interp1d - https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html#scipy-interpolate-interp1d
The constructor has three forms. Arguments should be supplied by keyword:
# Built-in analytic waveform
gprMax.Waveform(wave_type='ricker', amp=1, freq=1e9, id='pulse')
# MATLAB-default Gaussian-modulated cosine (50% bandwidth at -6 dB)
gprMax.Waveform(wave_type='gauspulse', amp=1, freq=1e9, id='rf_pulse')
# User-defined Python function
gprMax.Waveform(wave_type='user', user_func=function, id='pulse')
# User-defined sample arrays
gprMax.Waveform(
wave_type='user', user_values=values, user_time=times,
kind='linear', fill_value=0, id='pulse'
)
The callable keyword is user_func (not usr_func). It provides a bespoke waveform shape as an alternative to the user_values/user_time sample arrays and is available only through the Python API because a function object cannot be represented in a text input file. The callable must accept one scalar time in seconds and return the complete numeric amplitude at that time; amp and freq are therefore not required for wave_type='user'.
For example, the following creates a callable waveform and assigns it to a Hertzian dipole:
import numpy as np
import gprMax
def my_waveform(time):
return np.sin(2 * np.pi * 1e9 * time) * np.exp(-time / 1e-9)
scene.add(gprMax.Waveform(wave_type='user', user_func=my_waveform, id='mywave'))
scene.add(gprMax.HertzianDipole(
p1=(0.05, 0.05, 0.05), polarisation='z', waveform_id='mywave'
))
gprMax first calls the function at \(t=0\) to check its signature and return type. It is then sampled at the whole and/or half time steps required by each source while the source arrays are prepared. It is never called from the FDTD time-stepping loop, although a computationally expensive function can increase model setup time. Imports used by the function must be available in the scope where the function is defined, following normal Python name resolution.
The callable can also be a closure, which is a convenient way to generate a family of related waveforms without duplicating code:
def make_waveform(freq, decay):
def waveform(time):
return np.sin(2 * np.pi * freq * time) * np.exp(-time / decay)
return waveform
for i, freq in enumerate([0.5e9, 1e9, 2e9, 4e9]):
scene.add(gprMax.Waveform(
wave_type='user', user_func=make_waveform(freq, decay=1e-9), id=f'wave_{i}'
))
Exactly one of user_func and user_values must be supplied. When
user_values is used without user_time, gprMax associates the samples
with exactly iterations times, arange(iterations) * dt. The number of
values must match; supply an explicit, strictly increasing user_time for
another sampling grid. Sampled waveforms default to linear interpolation
inside the supplied time axis and zero outside it. kind and
fill_value override those defaults (including explicit 'extrapolate')
and apply only to sampled waveforms. Numeric fill values are honoured outside
both ends of the time axis. Callables retain their own boundary behaviour.
User-defined
waveforms can drive local Hertzian or magnetic dipoles, voltage sources,
transmission lines, and magnetic-frill sources. The discrete-plane-wave
formulation currently requires a built-in analytic waveform.
Hard voltage sources evaluate only whole-step samples, including the initial electric field at time zero. Resistive voltage sources and Hertzian dipoles use their existing half-step current samples; a final half-step outside a sampled waveform’s time axis uses the selected fill value. Zero waveform amplitude does not remove an active hard-source clamp: its start/stop window still controls whether the electric edge is prescribed.
For a Gaussian envelope with a cosine carrier, see the
modulated Gaussian waveform example.
It includes the built-in gauspulse definition, time trace, power spectrum,
intrinsic delay, and a custom-bandwidth callable. The built-in pulse uses
MATLAB’s default fractional bandwidth of 0.5 at -6 dB and starts at the
-60 dB envelope level; its peak occurs about 2.781 / freq seconds after
the source start time.
Eigenmode band, ports, excitation, and virtual guides
- class gprMax.user_objects.cmds_multiuse.EigenmodeBand(**kwargs)
Define the frequency band and optional extra DFT bins shared by all ports.
pointsselects equally spaced output frequencies fromfmintofmax, including both endpoints.frequenciesadds specific values within that range. The combined list is sorted from low to high, with repeated values included only once.- id
unique identifier for the shared eigenmode band.
- fmin
lower direct-DFT frequency in Hz.
- fmax
upper direct-DFT frequency in Hz.
- points
number of equally spaced output frequencies, including both endpoints.
- frequencies
optional additional direct-DFT frequencies in Hz. Values must lie between fmin and fmax inclusive and are added to the equally spaced frequencies selected by points.
- transition
positive transition width in Hz for an automatically generated bandpass waveform, or
"auto"(default).
- spectral_threshold
relative spectral threshold used to determine significant excitation support. The default is
1e-3.
Argument |
Default |
Meaning and constraints |
|---|---|---|
|
Required |
Non-empty identifier without whitespace. Exactly one band is allowed per grid. |
|
Required |
Positive, finite frequency limits with |
|
Required |
Number of equally spaced output frequencies from |
|
No extra frequencies |
Extra output frequencies in Hz, between |
|
|
Automatic pulse transition width, or a positive finite width in Hz. |
|
|
Relative amplitude threshold for significant waveform spectral support; strictly between zero and one. |
- class gprMax.user_objects.cmds_multiuse.EigenmodePort(**kwargs)
Define a modal port plane with its own anchor-frequency policy.
- port
positive, one-based port number.
- p1
first physical
(x, y, z)corner of the port plane.
- p2
opposite physical
(x, y, z)corner of the port plane.
- direction
launch/monitor direction normal to the plane,
+or-.
- modes
positive integer mode count or an increasing sequence of one-based mode indices.
- anchors
"auto"(default), one frequency, or an increasing sequence of modal-solve anchor frequencies in Hz.
- plot_fields
optionally force or suppress modal-field plots.
Noneretains the geometry-only default.
- degenerate
optional legacy mode pair or disjoint groups tracked as subspaces; ignored when
tracking="auto".
- mode_polarizations
optional global transverse E axis or real three-vector shared by the first member of every resolved doublet; the second uses positive port normal cross that direction. Automatic tracking resolves subgroups before polarization; legacy tracking uses declared pairs. Shared two-direction sequences in both trackers and mode/group mappings in legacy tracking emit a deprecation warning and will be removed in gprMax 5.0. Explicit pairs retain both signs and valid nonorthogonal directions. None preserves the current assignment. Physical selection requires a 3D cross-section and independent transverse directions.
- tracking
"legacy"(default) or experimental"auto"branch tracking, including automatic symmetry detection and selection for eligible degenerate spans.
- verification
"full"or"fast"quality checks for automatic tracking.
- tracking_config
optional
gprMax.EigenmodeTrackingConfigor mapping.
Port and outputs
EigenmodePort / #eigenmode_port defines both the modal basis and
monitor; EigenmodeExcitation selects what is driven. Each numbered port
writes /eigenmode_ports/portN (under /subgrids/<subgrid ID> for an
owning HSG grid). frequency, incident and outgoing are modal
spectra, not lumped voltage/current histories. Follow ModeIndices and
the stored power matrices; do not assign an arbitrary 50 Ohm circuit reference.
With one active channel, per-port S arrays describe responses to that
channel. Multiple simultaneous drives produce active reflection data, not a
complete S matrix; fully passive virtual ports produce raw spectra without S.
Use coefficient_valid_S for coefficient inspection and
power_wave_valid_S for propagating-power interpretation. Below-cutoff
coefficients must not be interpreted as transmitted power.
Use the modal plots and post-processing examples in Eigenmode ports and S-parameter analysis,
not the conventional plot_port tool. See Eigenmode-port and S-parameter output
for shapes and files and Eigenmode-port studies and array synthesis for complete matrices and
array synthesis. Ports must satisfy the owning grid/backend restrictions in
the eigenmode guide.
Ports using automatic tracking also write a versioned mode_tracking group.
It contains original candidate mappings, overlaps, residuals, requested and
adaptive frequencies, and per-anchor confinement/artifact diagnostics. These
quality records do not alter the established anchor_mode_valid or power-wave
masks; they explain warnings about anchors that remain in use.
Argument |
Default |
Meaning and constraints |
|---|---|---|
|
Required |
Unique positive, one-based port number within the grid. |
|
Required |
Opposite physical corners of an axis-aligned aperture. Exactly one finite coordinate must match, defining its normal; the invariant 2D axis is ignored in that test. |
|
Required |
|
|
Required |
An increasing sequence of unique positive mode indices, or a positive integer mode count. |
|
|
One modal solve frequency, an increasing sequence of positive finite frequencies, or automatic candidate selection. |
|
|
|
|
|
Experimental |
|
|
Applies only with automatic tracking. |
|
|
Optional |
|
|
Legacy tracking only: a group such as |
|
|
Optional single transverse axis ( |
- class gprMax.user_objects.cmds_multiuse.EigenmodeExcitation(**kwargs)
Attach one active modal drive to a defined port.
Several excitations may share the same base waveform and drive different port/mode channels. Each physical port is solved and monitored only once; its additional drives reuse the cached modal anchor bank.
- Parameters
port – One-based
EigenmodePortnumber.mode – One of the modes monitored by that port.
waveform – Shared waveform ID, or
'auto'for the bandpass pulse.amplitude – Non-zero modal amplitude scale. Mutually exclusive with
power.power – Optional relative incident-power scale; applies amplitude
sqrt(power).phase_deg – Constant spectral phase in degrees.
delay_s – True time delay in seconds, applied as
exp(-1j * 2*pi*f*delay_s).plot_waveform – Write or suppress this drive’s waveform/DFT plot. The default writes it only for geometry-only runs.
Port and outputs
EigenmodePort / #eigenmode_port defines both the modal basis and
monitor; EigenmodeExcitation selects what is driven. Each numbered port
writes /eigenmode_ports/portN (under /subgrids/<subgrid ID> for an
owning HSG grid). frequency, incident and outgoing are modal
spectra, not lumped voltage/current histories. Follow ModeIndices and
the stored power matrices; do not assign an arbitrary 50 Ohm circuit reference.
With one active channel, per-port S arrays describe responses to that
channel. Multiple simultaneous drives produce active reflection data, not a
complete S matrix; fully passive virtual ports produce raw spectra without S.
Use coefficient_valid_S for coefficient inspection and
power_wave_valid_S for propagating-power interpretation. Below-cutoff
coefficients must not be interpreted as transmitted power.
Use the modal plots and post-processing examples in Eigenmode ports and S-parameter analysis,
not the conventional plot_port tool. See Eigenmode-port and S-parameter output
for shapes and files and Eigenmode-port studies and array synthesis for complete matrices and
array synthesis. Ports must satisfy the owning grid/backend restrictions in
the eigenmode guide.
Ports using automatic tracking also write a versioned mode_tracking group.
It contains original candidate mappings, overlaps, residuals, requested and
adaptive frequencies, and per-anchor confinement/artifact diagnostics. These
quality records do not alter the established anchor_mode_valid or power-wave
masks; they explain warnings about anchors that remain in use.
Argument |
Default |
Meaning and constraints |
|---|---|---|
|
Required |
Existing port and one of its monitored modes. Each driven channel must be unique. |
|
|
Band-adapted finite pulse, or the ID of an explicitly added |
|
|
Finite nonzero modal-amplitude scale. Omit the excitation to make a channel passive. |
|
Not set |
Positive finite relative incident-power scale, applying amplitude |
|
|
Finite constant spectral phase in degrees. |
|
|
Finite true time delay in seconds, applied as |
|
|
Force or suppress the waveform/spectrum PNG with |
- class gprMax.user_objects.cmds_multiuse.VirtualWaveguide(port, length_cells=30, pml_cells=12, source_clearance_cells=6, pml_profile=None)
Terminate an eigenmode port with a bidirectionally coupled FDTD guide.
The guide repeats the material cross-section at the referenced
EigenmodePort, couples both E and H fields at its aperture, and terminates its remote end with a PML. It can contain the active modal source or act as a passive matched receiver.- Parameters
port – One-based eigenmode-port number.
length_cells – Total virtual-guide length in cells. Default 30.
pml_cells – PML thickness at the remote end. Default 12.
source_clearance_cells – Cells between an active internal source plane and the PML. Default 6.
pml_profile – Optional reusable PML profile ID.
Argument |
Default |
Meaning and constraints |
|---|---|---|
|
Required |
Positive, one-based number of an existing |
|
|
Total auxiliary-guide length, including its PML and source clearance. A positive integer, at least |
|
|
Thickness of the auxiliary guide’s absorbing layer at the end away from the port. An integer of at least 2 cells. |
|
|
Distance between the internal source plane and the start of that PML. A positive integer number of cells, at least 1. |
|
|
Name of an existing reusable PML profile. |
- class gprMax.user_objects.cmds_output.EigenmodeFieldOutput(filename='port_modes', ports=())
Export tracked modal E/H bases during a serial 3D model build.
filenameis a basename in the run output directory;portsdefaults to all prepared physical ports. No field time stepping is required.
Use scene.add(gprMax.EigenmodeFieldOutput(filename="bank", ports=(1, 2)))
to export prepared tracked modal profiles to bank.modes.h5 in the run
output directory, including during geometry-only runs. Omit ports to
export all prepared physical ports; filename defaults to port_modes.
Export requires a serial 3D main grid. The equivalent hash command and output
restrictions are described under #eigenmode_field_output:.
A band selects output frequencies; a port defines a reference plane and monitored modes; an excitation drives a channel; a virtual guide provides a separate matched continuation. The full workflows and equivalent hash commands are in Eigenmode ports and S-parameter analysis. See Model Building for the complete command syntax, Model Output for stored arrays, and Eigenmode ports: theory and numerical methods for numerical methods.
A direct eigenmode model may also be placed wholly inside one HSG subgrid.
Add its band, ports, waveform (when one is used), and excitation to that same
subgrid object. With autotranslate=True, the plane coordinates remain
global physical coordinates:
fine_grid.add(gprMax.Waveform(
wave_type='contsine', amp=1, freq=22e9, id='fine_wave',
))
fine_grid.add(gprMax.EigenmodeBand(
id='fine_band', fmin=22e9, fmax=22e9, points=1,
))
fine_grid.add(gprMax.EigenmodePort(
port=1,
p1=(0.045, 0.039, 0.039),
p2=(0.045, 0.051, 0.049),
direction='+', modes=(1,), anchors=(22e9,),
))
fine_grid.add(gprMax.EigenmodeExcitation(
port=1, mode=1, waveform='fine_wave',
))
The FDFD solver samples the final component-resolved material slice of the
fine Yee grid and uses its two transverse spatial steps. Injection and modal
observation then run at every fine-grid time step. The complete plane and its
adjacent staggered Yee stencil must lie strictly inside the subgrid working
region; a plane touching the HSG coupling surface or entering its auxiliary
or PML region is rejected. Ports cannot be divided between the main grid and
a subgrid, or between different subgrids. VirtualWaveguide can be added
to the same subgrid and referenced to one of its ports. The auxiliary guide
then inherits the fine grid’s spatial and temporal steps, material
cross-section, update coefficients, and iteration count; it is not resampled
from the coarse main grid.
Voltage Source
- class gprMax.user_objects.cmds_multiuse.VoltageSource(p1: Tuple[float, float, float], polarisation: str, resistance: float, waveform_id: str, start: Optional[float] = None, stop: Optional[float] = None, id: Optional[str] = None, spectrum_limit=10.0, reference_impedance: Optional[float] = None)
Specifies a voltage source at an electric field location.
In a 3-D model the source also owns an automatic terminal monitor. A hard source on a domain-minimum transverse boundary remains a valid source, but cannot provide that port output because its complete Ampere loop lies partly outside the grid.
- polarisation
string required for polarisation of the source x, y, z.
- p1
tuple required for position of source x, y, z.
- resistance
float required for internal resistance (Ohms) of voltage source.
- waveform_id
string required for identifier of waveform used with source.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
- id
optional HDF5 port identifier. If omitted,
portNis assigned.
- spectrum_limit
minimum cells per shortest material wavelength (default 10), or
"nyquist"for the full research spectrum.
- reference_impedance
float optional wave-reference impedance (Ohms) for a hard source. The default is 50 Ohms. This final argument is not accepted for a finite-resistance source, whose physical resistance is also its wave-reference impedance.
- property result
Return the automatic port result after the model has solved.
Port and outputs
In a supported 3-D model this source automatically writes
/ports/<id> (default ID portN); no extra Rx is needed. A CPU or CUDA HSG
port is below /subgrids/<subgrid ID>/ports/<id>. A hard source on a
domain-minimum transverse boundary remains an excitation but has no automatic
port because its full magnetic-current loop is unavailable. Reduced 2-D
sources do not provide this port output.
Vtotal is gap voltage in volts, with sign opposite to the electric-field
component along the source edge. Use its stored time axis. Finite-resistance
ports use half-step-aligned voltage histories; hard ports retain voltage at
time zero and a separately staggered Iloop history on time_current.
frequency, S11, Zin and Yin are the corrected terminal spectra,
with separate valid_S11, valid_Zin and valid_Yin masks.
The Python source’s result provides time, total_voltage,
frequency, s11, zin, yin and their lowercase validity masks
after solving. The finite source’s resistance is its reference impedance;
a hard source’s independent reference impedance defaults to 50 Ohms.
A zero-amplitude finite-resistance source remains a passive load and reports
received voltage, but its own source-normalised S11/impedance is not a valid
input characterisation. Zero amplitude with zero resistance is a clamp.
python -m gprMax.toolboxes.Plotting.plot_port model.h5 --port feed --validity --save
Replace feed with the actual ID. See Voltage-port equations and timing for
correction, timing and support details, Voltage-source S11 and impedance output for the
schema, and Finite-resistance voltage-port studies for a complete multiport matrix.
A finite-resistance voltage source is a one-cell Thévenin gap source. It also
acts as a port: after a supported 3-D simulation, source.result provides
the sampled gap voltage together with the frequency-domain port
quantities. Its physical resistance is the wave-reference impedance. A zero
resistance creates a hard source with an independent wave-reference
impedance: reference_impedance defaults to 50 Ohms and does not add a
physical resistance to the gap.
feed = gprMax.VoltageSource(
p1=(0.05, 0.05, 0.02),
polarisation='z',
resistance=50,
waveform_id='pulse',
id='feed',
)
scene.add(feed)
The waveform amplitude is the generator voltage in volts. See #voltage_source for the one-cell source equation and the definition of the automatic port spectra.
A hard source also prescribes the initial electric field before sample zero
is stored. Subsequent prescriptions use the new electric time level
\((n+1)\Delta t\). start and stop are inclusive at these physical
times. A zero waveform still clamps the edge while active; start=0 and
\(0<\mathtt{stop}<\Delta t\) apply only the initial impulse and then release
the edge. In a subgrid, use its local \(\Delta t\).
Voltage-source S11 and input impedance
Every 3-D single-Yee-edge gprMax.VoltageSource normally owns the
necessary hidden field monitor and calculates corrected complex S11,
Zin, and Yin after the solve. The exception is a zero-resistance hard
source on a domain-minimum transverse boundary: the source remains valid, but
gprMax warns and omits its automatic port because the complete Ampere current
loop lies partly outside the grid. A finite-resistance source uses its
physical resistance as the reference impedance:
port = gprMax.VoltageSource(
p1=(0.050, 0.050, 0.020),
polarisation='z',
resistance=50,
waveform_id='source_wave',
id='feed',
spectrum_limit=10,
)
scene.add(port)
The default spectrum_limit=10 retains frequencies having at least ten
cells per shortest material wavelength. A research run can explicitly request
all native non-negative FFT bins while retaining the normal validity metadata:
scene.add(gprMax.VoltageSource(
p1=(0.050, 0.050, 0.020),
polarisation='z', resistance=50,
waveform_id='source_wave',
id='feed_full',
spectrum_limit='nyquist',
))
A hard voltage source can instead emulate an ideal MoM delta-gap excitation. Set the source resistance to zero. Its travelling-wave reference impedance defaults to 50 Ohms and can be changed on the source:
scene.add(gprMax.VoltageSource(
p1=(0.050, 0.050, 0.020),
polarisation='z',
resistance=0,
waveform_id='source_wave',
id='ideal_feed',
reference_impedance=50,
))
After gprMax.run completes, port.result provides the same numerical
arrays that are stored under /ports/feed in the model HDF5 file. For a
hard source, gprMax obtains terminal current from the surrounding magnetic-
field loop and accounts explicitly for the half-step phase difference from
the integer-time voltage during transformation.
A finite-resistance source on a dispersive edge includes the background material’s complete complex permittivity in the Yee-gap correction. The same correction is used for terminal current and accepted power when calculating antenna parameters or normalising SAR. A hard source on a dispersive edge is not yet supported because its sampled Ampere-loop current requires the discrete polarisation-current contribution to be separated explicitly.
The automatic voltage-source port also supports domain-decomposed MPI CPU
models. The owning rank
stores the voltage history; hard-source current loops may cross internal rank
faces because magnetic halos are synchronised before sampling. Histories are
gathered and transformed once on the coordinator rank, while port.result
is rebound to that final result for Python API use.
The source may also be placed inside a SubGridHSG. Add the waveform and
voltage source to the subgrid object; the port is then sampled
using that subgrid’s finer spatial and temporal discretisation. With
autotranslate=True, the port and source use the same global physical
coordinate:
subgrid.add(gprMax.Waveform(
wave_type='ricker', amp=1, freq=5e9, id='feed_wave'
))
subgrid.add(gprMax.VoltageSource(
p1=(0.090, 0.070, 0.060),
polarisation='z', resistance=50,
waveform_id='feed_wave',
id='fine_feed',
))
The result is stored at
/subgrids/<subgrid ID>/ports/<port ID>. The source belongs to the owning
grid object, so its discretised coordinate, material edge,
dl, and dt are unambiguous.
Hertzian Dipole Source
- class gprMax.user_objects.cmds_multiuse.HertzianDipole(p1: Tuple[float, float, float], polarisation: str, waveform_id: str, start: Optional[float] = None, stop: Optional[float] = None)
Specifies a current density term at an electric field location.
The simplest excitation, often referred to as an additive or soft source.
- polarisation
string required for polarisation of the source x, y, z.
- p1
tuple required for position of source x, y, z.
- waveform_id
string required for identifier of waveform used with source.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
Outputs (no circuit port)
This ideal impressed-current source does not create a circuit port, S11 or
input impedance. Add Rx / #rx for field or Ampere-loop observations,
or an NTFF request for transformed fields. Raw field/source ratios are not
power-wave S-parameters. See Sources and ports for source selection and
GPR acquisitions for point-source acquisition schedules.
This additive electric source uses the waveform amplitude as current \(I\) in amperes and an effective dipole length equal to the cell step in the selected direction. It therefore impresses
For example:
scene.add(gprMax.HertzianDipole(
p1=(0.05, 0.05, 0.05),
polarisation='z',
waveform_id='pulse',
))
It is an ideal field excitation, not a circuit port, and consequently does not produce S-parameters or an input impedance.
Magnetic Dipole Source
- class gprMax.user_objects.cmds_multiuse.MagneticDipole(p1: Tuple[float, float, float], polarisation: str, waveform_id: str, start: Optional[float] = None, stop: Optional[float] = None)
Simulates an infinitesimal magnetic dipole.
Often referred to as an additive or soft source.
- polarisation
string required for polarisation of the source x, y, z.
- p1
tuple required for position of source x, y, z.
- waveform_id
string required for identifier of waveform used with source.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
Outputs (no circuit port)
This ideal impressed-current source does not create a circuit port, S11 or
input impedance. Add Rx / #rx for field or Ampere-loop observations,
or an NTFF request for transformed fields. Raw field/source ratios are not
power-wave S-parameters. See Sources and ports for source selection and
GPR acquisitions for point-source acquisition schedules.
This is the magnetic-current dual of the additive Hertzian source. It is placed at a magnetic Yee-field location and does not represent a circuit port. For example:
scene.add(gprMax.MagneticDipole(
p1=(0.05, 0.05, 0.05),
polarisation='y',
waveform_id='pulse',
))
The permitted source component and invariant-axis index in a 2-D model follow the surviving TM or TE magnetic-field components and are validated when the scene is built.
Rational lumped-network terminal
- class gprMax.user_objects.cmds_multiuse.RationalNetwork(id: str, conductance: float = 0.0, capacitance: float = 0.0, poles=(), residues=(), allow_active: bool = False)
Define a reusable rational one-port admittance.
- Parameters
id – Unique network-model identifier.
conductance – Direct conductance \(G\) in siemens.
capacitance – Direct capacitance \(C\) in farads.
poles – Sequence of poles \(p_m\) in radians per second.
residues – Sequence of residues \(r_m\) paired with
poles.allow_active – Permit coefficients which do not satisfy the normal passive-network checks. The default is
False.
- class gprMax.user_objects.cmds_multiuse.NetworkTerminal(p1: Tuple[float, float, float], polarisation: str, network_id: str, id: str)
Connect a rational network model to one electric Yee edge.
- Parameters
p1 – Physical
(x, y, z)position of the electric edge.polarisation – Electric-edge direction,
x,y, orz.network_id – Identifier of a preceding
RationalNetwork.id – Unique terminal and HDF5 port identifier.
- class gprMax.user_objects.cmds_multiuse.NetworkExcitation(terminal_id: str, waveform_id: str, start: Optional[float] = None, stop: Optional[float] = None)
Apply a Thevenin open-circuit waveform to a network terminal.
- Parameters
terminal_id – Identifier of a preceding
NetworkTerminal.waveform_id – Identifier of the driving waveform.
start – Optional source start time in seconds.
stop – Optional source stop time in seconds.
Port and outputs
Output is explicit: add #network_port: feed or
scene.add(gprMax.NetworkPort(terminal_id='feed')) for terminal feed.
The network and its excitation alone do not request port results. Output is
/ports/feed, or /subgrids/<subgrid ID>/ports/feed for a CPU or CUDA HSG port.
time, Vgenerator, Vtotal and Inetwork describe the generator,
gap voltage (V) and network current (A). Terminal-current spectra remove the
background Yee-gap admittance and are distinct from the external-network
current. frequency, S11, Zin and Yin have independent validity
masks. Reference impedance defaults to 50 Ohms; it does not replace the
physical network admittance.
Keep the NetworkPort object to read port.result.total_voltage,
port.result.s11, port.result.zin and the other result arrays after
solving. Omitting NetworkExcitation leaves a passive measurable load:
its received voltage/current remain useful, but source-normalised S11 is
undefined. Impedance/admittance are available where their own masks permit.
Use python -m gprMax.toolboxes.Plotting.plot_port model.h5 --port feed --save.
See Rational-network port output for the schema, Fixed-topology terminal-source studies for
fixed-network drive studies and Ports, antenna power and NTFF for NTFF use.
RationalNetwork defines the reusable driving-point admittance
NetworkTerminal places it on one electric Yee edge. It is passive unless
a NetworkExcitation supplies a Thévenin open-circuit waveform. For
example, a 50 Ohm driven port is
scene.add(gprMax.RationalNetwork(
id='source50', conductance=1 / 50, capacitance=0,
))
scene.add(gprMax.NetworkTerminal(
p1=(0.05, 0.05, 0.02), polarisation='z',
network_id='source50', id='feed',
))
scene.add(gprMax.NetworkExcitation(
terminal_id='feed', waveform_id='pulse',
))
network_port = gprMax.NetworkPort(terminal_id='feed')
scene.add(network_port)
An inductor is represented by poles=(0,) and residues=(1/L,);
a series \(RL\) branch uses poles=(-R/L,) and
residues=(1/L,). Complex terms must be supplied as conjugate pairs.
The circuit-to-edge formulation follows the arbitrary linear lumped-network
FDTD approaches of [PER1999] and [CHE2007]. Their underlying classic PLRC
time discretisation is improved here using the exponential recursive-
convolution treatment of Giannakis and Giannopoulos [GIA2014]: every pole
current is evaluated analytically at the electric half-step for a linearly
varying voltage, rather than estimated by averaging its two integer-time
values. State is stored only for placed terminals. Independent one-port
rational networks are supported in 3-D on the CPU, CUDA, OpenCL, and Metal
solvers, including domain-decomposed MPI CPU models; terminals inside
HSG subgrids use the CPU or CUDA solver. An MPI terminal is advanced only on
the rank that owns its electric edge, and its histories are gathered for port
post-processing. Device runs keep the network recurrence and field correction
on the compute device
and copy the completed histories back after the solve. Coupled multiport
admittance matrices are reserved for a later extension.
For \(Y=1/R\), NetworkExcitation and a conventional finite-resistance
VoltageSource are the same discrete Thévenin source when their position,
resistance, and waveform are identical. This equivalence does not apply to a
zero-resistance hard voltage source.
Transmission Line
- class gprMax.user_objects.cmds_multiuse.TransmissionLine(p1: Tuple[float, float, float], polarisation: str, resistance: float, waveform_id: str, start: Optional[float] = None, stop: Optional[float] = None)
- Specifies a one-dimensional transmission line model at an electric
field location. The source is supported by the CPU and CUDA solvers.
- polarisation
string required for polarisation of the source x, y, z.
- p1
tuple required for position of source x, y, z.
- resistance
float required for internal resistance (Ohms) of voltage source.
- waveform_id
string required for identifier of waveform used with source.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
Port and outputs
The source automatically writes /tls/tlN in creation order, or
/subgrids/<subgrid ID>/tls/tlN for a CPU or CUDA HSG source. Vinc and
Vtotal are incident and total line voltages (V); Iinc and Itotal
are line currents (A). These are terminal quantities, not a point receiver’s
local electric/magnetic fields. The line resistance is the reference impedance.
frequency, S11, Zin, Yin and their validity masks are already
calculated. Zin_current is an independent current-wave de-embedding check;
do not reconstruct it by simply dividing raw staggered histories. Use
python -m gprMax.toolboxes.Plotting.plot_port model.h5 --port tls/tl1 --save
to inspect the stored result and its timing. See Transmission-line S11 and impedance output for
the line’s spatial/temporal reference plane and masks, and Fixed-topology terminal-source studies
for changing generator drives while retaining the passive line termination.
Every transmission-line source automatically writes its incident and terminal
voltage/current histories together with frequency, S11, Zin, and
Yin beneath /tls/tlN in the model HDF5 output. Zin is derived from
the voltage-wave S11 result; Zin_current is an independent, stagger-aware
current-wave check. Voltage and transmission-line sources both own their
terminal outputs, so no separate receiver-port object is required. See
Simulation Output for the equations and validity masks.
Magnetic Frill Source
- class gprMax.user_objects.cmds_multiuse.MagneticFrillSource(p1: Tuple[float, float, float], polarisation: str, zcoax: float, waveform_id: str, start: Optional[float] = None, stop: Optional[float] = None, spectrum_limit=10.0)
- Specifies a magnetic-frill (equivalent-feed) source at an electric
field location, for an antenna fed through a PEC ground plane by a coaxial line. Complements #transmission_line: a different, well-established formulation (not a variant of the two-wire line - no 1D line, no ABC, no magic timestep). The corrected Hyun feed-cell formulation is supported by the CPU, CUDA, OpenCL, and Metal solvers, and by the CPU and CUDA subgrid updaters.
- polarisation
string required for polarisation of the source - x, y, or z (the antenna axis the source drives current along, following the same electrical sign convention as gprMax’s Ix/Iy/Iz current output).
- p1
tuple required for position of source x, y, z.
- zcoax
float required for the coax’s characteristic impedance (Ohms), calculated from its physical radii and filler. The inner radius used by the discrete feed cell is inferred from a co-located ThinWire with the same polarisation.
- waveform_id
string required for identifier of waveform used with source.
- start
float optional delay before the incident waveform starts (secs).
- stop
float optional time at which the incident waveform stops (secs). The coaxial terminal relation remains active afterwards.
- spectrum_limit
minimum cells per shortest material wavelength (default 10), or
"nyquist"for the full research spectrum.
Port and outputs
The source automatically writes /frills/frillN in creation order, or
/subgrids/<subgrid ID>/frills/frillN for a CPU or CUDA HSG source. Vinc is
half the generator waveform (V), Vtotal is the solved terminal voltage
(V), and Itot is the feed current (A), centred using adjacent magnetic
half steps. Zcoax is the wave-reference impedance. This continuous-wire,
through-ground-plane feed is not an electric gap source.
frequency, S11, Zin, Yin and their per-quantity validity masks
are stored directly. Use
python -m gprMax.toolboxes.Plotting.plot_port model.h5 --port frills/frill1 --save;
see Magnetic-frill-source S11 and impedance output for the sampling convention and full schema.
A zero generator leaves the frill termination present; Fixed-topology terminal-source studies
can vary the drive without rebuilding its physical definition.
A magnetic frill represents a sub-cell coaxial aperture through a PEC ground
plane. It must share an axial Yee edge with a ThinWire; the source uses
that object’s physical radius \(a\) in Hyun’s feed-cell equation. The
zcoax argument is the characteristic impedance of the physical coax. For
a lossless TEM coax with outer-conductor inner radius \(b\) and filler
properties \(\varepsilon_{r,c}\) and \(\mu_{r,c}\),
For the usual nonmagnetic filler,
The filler permittivity is the value inside the coax, which need not equal the
antenna-side material above the ground plane. gprMax obtains \(a\) from
ThinWire; \(b\) is not an input and the user must confirm that the
resulting aperture remains sub-cell. For example:
scene.add(gprMax.Waveform(
wave_type='ricker', amp=1, freq=1e9, id='pulse'
))
scene.add(gprMax.Plate(
p1=(0, 0, 0.02), p2=(0.10, 0.10, 0.02), material_id='pec'
))
scene.add(gprMax.ThinWire(
p1=(0.05, 0.05, 0.02), p2=(0.05, 0.05, 0.08), radius=0.0001
))
scene.add(gprMax.MagneticFrillSource(
p1=(0.05, 0.05, 0.02), polarisation='z', zcoax=50,
waveform_id='pulse',
))
The corrected formulation is supported by the CPU, CUDA, OpenCL, and Metal
solvers and by domain-decomposed MPI CPU models. Its four magnetic feed edges
may cross internal MPI rank boundaries, and PMC image completion is supported
at minimum-face symmetry corners. It is also supported inside a CPU or CUDA
SubGridHSG. Add the waveform, PEC ground plane, thin wire, and magnetic
frill to the same subgrid object,
using the same global-coordinate convention as other subgrid sources when
autotranslate=True:
subgrid.add(gprMax.Waveform(
wave_type='ricker', amp=1, freq=5e9, id='fine_feed_wave'
))
subgrid.add(gprMax.Plate(
p1=(0.08, 0.06, 0.05), p2=(0.10, 0.08, 0.05),
material_id='pec',
))
subgrid.add(gprMax.ThinWire(
p1=(0.09, 0.07, 0.05), p2=(0.09, 0.07, 0.06),
radius=0.0001,
))
subgrid.add(gprMax.MagneticFrillSource(
p1=(0.09, 0.07, 0.05), polarisation='z', zcoax=50,
waveform_id='fine_feed_wave',
))
The complete frill stencil and attached wire should remain within the
subgrid’s working region; objects traversing its outer surface produce the
usual advanced-use warning, while thin-wire or frill placement in its PML is
rejected. Symmetry boundaries are not supported on a subgrid, so subgrid
frills cannot use symmetry-plane completion. The source
writes its time-domain terminal histories and derived S11, Zin, and
Yin automatically beneath /frills/frillN on the main grid or
/subgrids/<subgrid ID>/frills/frillN on a subgrid. See
Simulation Output.
All local sources refer to the ID of a waveform that has already been added to the scene. The following illustrates their required arguments; a model would normally contain only the source or sources that it needs:
scene.add(gprMax.Waveform(
wave_type='ricker', amp=1, freq=1e9, id='pulse'
))
scene.add(gprMax.VoltageSource(
p1=(0.04, 0.05, 0.05), polarisation='z', resistance=50,
waveform_id='pulse',
))
scene.add(gprMax.HertzianDipole(
p1=(0.05, 0.05, 0.05), polarisation='z', waveform_id='pulse'
))
scene.add(gprMax.MagneticDipole(
p1=(0.06, 0.05, 0.05), polarisation='y', waveform_id='pulse'
))
scene.add(gprMax.TransmissionLine(
p1=(0.07, 0.05, 0.05), polarisation='z', resistance=50,
waveform_id='pulse',
))
Plane Wave Angles
- class gprMax.user_objects.cmds_multiuse.DiscretePlaneWaveAngles(**kwargs)
Specifies a plane wave implemented using the discrete plane wave formulation. If the background material is not specified it will default to free space. The wave will propagate in the direction given by the angles theta and phi with a polarisation given by the angle psi.
- theta
float required for propagation angle (degrees) of wave.
- phi
float required for propagation angle (degrees) of wave.
- psi
float required for polarisation of wave.
- max_angle_diff
float optional for tolerance of maximum acceptable angular difference between the desired direction of the wavevector and the estimated direction of it (degrees). Default is 3 arc minutes (0.05 degrees).
- p1
tuple required for the lower left position (x, y, z) of the total field, scattered field (TFSF) box.
- p2
tuple required for the upper right position (x, y, z) of the total field, scattered field (TFSF) box.
- waveform_id
string required for identifier of waveform used with source.
- material_id
string optional of material identifier to use as the background material in the TFSF box.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
- precompute
boolean optional. If
True(default), precompute the auxiliary plane-wave source history before time stepping.Falseis reserved for a future on-the-fly implementation and is currently rejected.
Outputs (no circuit port)
A discrete plane wave does not create voltage/current ports or S-parameters. Use receivers inside/outside the TFSF box for total/scattered fields and NTFF outputs for scattering/RCS. The incident-wave normalisation is not antenna-port accepted-power normalisation. See NTFF field-transformation output and Plane-wave and RCS studies for angle/polarisation studies; every observation direction must be requested in the fixed output definition.
Plane Wave Vector
- class gprMax.user_objects.cmds_multiuse.DiscretePlaneWaveVector(**kwargs)
Specifies a plane wave implemented using the discrete plane wave formulation. If the background material is not specified it will default to free space. The wave will propagate in the direction given by the vector m_vec with a polarisation given by the angle psi. The vector m_vec should be of integer values and the direction of propagation will be in the direction of that vector.
- m_vec
tuple required of the three integer componets specifying the direction of the the plane wave.
- psi
float required for the polarisation of wave.
- p1
tuple required for the lower left position (x, y, z) of the total field, scattered field (TFSF) box.
- p2
tuple required for the upper right position (x, y, z) of the total field, scattered field (TFSF) box.
- waveform_id
string required for identifier of waveform used with source.
- material_id
string optional of material identifier to use as the background material in the TFSF box.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
- precompute
boolean optional. If
True(default), precompute the auxiliary plane-wave source history before time stepping.Falseis reserved for a future on-the-fly implementation and is currently rejected.
Outputs (no circuit port)
A discrete plane wave does not create voltage/current ports or S-parameters. Use receivers inside/outside the TFSF box for total/scattered fields and NTFF outputs for scattering/RCS. The incident-wave normalisation is not antenna-port accepted-power normalisation. See NTFF field-transformation output and Plane-wave and RCS studies for angle/polarisation studies; every observation direction must be requested in the fixed output definition.
Plane Wave Axial
- class gprMax.user_objects.cmds_multiuse.DiscretePlaneWaveAxial(**kwargs)
Specifies an axial plane wave implemented using the discrete plane wave formulation. No background material is specified as materials are copied directly by the existing grid values along the axial direction of propagation. The wave will propagate in one of the directions of the Cartesian axes of the grid (x, y or z) with a polarisation given by the angle psi.
- axis
a single character string required for defining the propagation axis of the wave x, y or z.
- psi
float required for polarisation of wave.
- p1
tuple required for the lower left position (x, y, z) of the total field, scattered field (TFSF) box.
- p2
tuple required for the upper right position (x, y, z) of the total field, scattered field (TFSF) box.
- waveform_id
string required for identifier of waveform used with source.
- start
float optional to delay start time (secs) of source.
- stop
float optional to time (secs) to remove source.
- precompute
boolean optional. If
True(default), precompute the auxiliary plane-wave source history before time stepping.Falseis reserved for a future on-the-fly implementation and is currently rejected.
Outputs (no circuit port)
A discrete plane wave does not create voltage/current ports or S-parameters. Use receivers inside/outside the TFSF box for total/scattered fields and NTFF outputs for scattering/RCS. The incident-wave normalisation is not antenna-port accepted-power normalisation. See NTFF field-transformation output and Plane-wave and RCS studies for angle/polarisation studies; every observation direction must be requested in the fixed output definition.
The angle, propagation-vector, and axial classes are alternative ways of describing a total-field/scattered-field plane wave. The two points define the total-field box. For example, choose one of:
scene.add(gprMax.DiscretePlaneWaveAngles(
theta=90, phi=0, psi=90,
p1=(0.02, 0.02, 0.02), p2=(0.08, 0.08, 0.08),
waveform_id='pulse',
))
scene.add(gprMax.DiscretePlaneWaveVector(
m_vec=(1, 0, 0), psi=90,
p1=(0.02, 0.02, 0.02), p2=(0.08, 0.08, 0.08),
waveform_id='pulse',
))
scene.add(gprMax.DiscretePlaneWaveAxial(
axis='x', psi=90,
p1=(0.02, 0.02, 0.02), p2=(0.08, 0.08, 0.08),
waveform_id='pulse',
))
Here pulse must identify a built-in analytic waveform. Discrete plane waves
use the CPU, CUDA, OpenCL, and Apple Metal solvers.
Homogeneous angle/vector plane waves and layered axial plane waves support
non-dispersive materials and multi-pole Debye, Lorentz, and Drude materials.
Their auxiliary dispersive state uses the same real or complex precision
selected for the main grid. A discrete plane wave must be added to the main
scene, not to a subgrid. Its TFSF box may contain a complete subgrid; where the
two regions overlap, the box must strictly enclose the subgrid’s HSG outer
coupling surface so that the TFSF correction stencil remains on the main grid.
MPI domain decomposition is supported. The auxiliary one-dimensional wave is
replicated on every rank, and each rank applies only the TFSF corrections for
the Yee components that it owns. For an axial plane wave, the layered material
profile is assembled once from the distributed grid’s actual update
coefficients, including multi-pole dispersive coefficients; no additional
plane-wave communication occurs during timestepping.
Excitation File
- class gprMax.user_objects.cmds_multiuse.ExcitationFile(filepath: Union[str, PathLike], kind: Optional[Union[int, str]] = None, fill_value: Optional[Union[float, str]] = None)
Specify file containing amplitude values of custom waveforms.
The file should be an ASCII file, and the custom waveform shapes can be used with sources in the model.
- filepath
Excitation file path.
- Type
str | PathLike
- kind
Optional interpolation kind passed to scipy.interpolate.interp1d.
- Type
int | str | None
- fill_value
Optional float value or ‘extrapolate’ passed to scipy.interpolate.interp1d.
- Type
float | str | None
scene.add(gprMax.ExcitationFile(
filepath='measured_waveforms.txt', kind='linear', fill_value=0
))
Receiver
- class gprMax.user_objects.cmds_multiuse.Rx(p1: Tuple[float, float, float], id: Optional[str] = None, outputs: Optional[List[str]] = None)
Specifies output points in the model.
These are locations where the values of the electric and magnetic field components over the numberof iterations of the model will be saved to file.
- p1
tuple required for position of receiver x, y, z.
- id
optional string used as identifier for receiver.
- outputs
optional list of outputs for receiver. It can be any selection from Ex, Ey, Ez, Hx, Hy, Hz, Ix, Iy, or Iz.
Receiver Array
- class gprMax.user_objects.cmds_multiuse.RxArray(p1: Tuple[float, float, float], p2: Tuple[float, float, float], dl: Tuple[float, float, float])
Defines multiple output points in the model.
- p1
tuple required for position of first receiver x, y, z.
- p2
tuple required for position of last receiver x, y, z.
- dl
tuple required for receiver spacing dx, dy, dz.
Specific absorption rate (SAR)
- class gprMax.user_objects.cmds_output.SAR(frequencies, waveform_id: str | None = None, tags=None, id: str = 'sar1', target_amplitude: float = 1.0, spectrum_limit=10.0, source_floor_db: float = -40.0, window: str = 'rectangular', averaging_masses=(), normalisation: str = 'waveform', port_id: str | None = None, target_power: float | None = None, target_flux: float | None = None)
Request frequency-domain SAR over one or more geometry tags.
The electric fields are transformed on the fly at the requested frequencies. Results are normalised to
target_amplitudeusing the spectrum of exactly one active source associated withwaveform_id, or to incident/accepted power fromport_id. Port-power normalisation does not require a waveform ID because the physical port result supplies its own spectral support and validity.Only electric absorption contributes to SAR. Magnetic properties still affect the FDTD fields, but magnetic absorption is not included. Selected magnetic materials outside PML, excluding ideal PMC constraints, trigger a warning. With nonzero magnetic loss, the result is not total SAR. Lossless permeability alone adds no magnetic heating.
- Parameters
frequencies – Strictly increasing positive frequencies in Hz.
waveform_id – Waveform attached to a source-normalised excitation. Required for
"waveform"and"current_moment"; optional and unused for port-power normalisation.tags – Geometry tag string or iterable of tag strings.
id – Unique HDF5 output identifier.
target_amplitude – Peak phasor amplitude represented by the normalised source spectrum.
spectrum_limit – Minimum cells per shortest material wavelength (default 10), or
"nyquist"for explicit research output.source_floor_db – Frequencies below this relative source-spectrum level are stored as invalid/NaN.
window –
"rectangular"or"hann".averaging_masses – Optional spatial averaging masses in kg. The default empty tuple writes local cell SAR only. For example,
(0.001, 0.01)requests the standard 1 g and 10 g results.normalisation –
"waveform"(default),"current_moment"for a 3-D Hertzian dipole,"incident_flux"for a discrete plane wave,"incident_power", or"accepted_power".port_id – Required for either power normalisation.
target_power – Required positive power for either power normalisation; watts in 3-D and watts per metre in 2-D.
target_flux – Required positive incident plane-wave power flux in W/m2 for
"incident_flux"normalisation.
See the electric-only absorption limitation for the magnetic-material warning and its scope, including directional materials and ideal PMC constraints.
Both isotropic and grid-aligned diagonal anisotropic volume materials are
supported. For a primitive with material_ids=(mx, my, mz), absorption is
the sum of the x-, y-, and z-component contributions using each material’s
frequency-dependent electric loss, not the mean of the three conductivities.
The three constituent materials must have the same positive mass density for
SAR. Missing or conflicting densities are rejected; Radiometry uses the
same electric absorption calculation without density. See Model Output for
the equations and the supported tensor convention.
SAR selects the final voxelised cells belonging to one or more semantic
geometry tags. Every selected material must first have a mass density in
kg/m3, assigned with MaterialDensity or supplied by a
material database. For example:
scene.add(gprMax.MaterialDensity(density=1040, material_ids=('brain',)))
scene.add(gprMax.SAR(
frequencies=np.linspace(0.8e9, 1.2e9, 41),
waveform_id='pulse',
tags=('brain_region',),
id='brain_sar',
target_amplitude=1.0,
spectrum_limit=10,
averaging_masses=(0.001, 0.01),
))
target_amplitude uses the source’s native excitation units. In
particular, it is incident electric-field amplitude in V/m for a discrete
plane wave and generator voltage in V for a voltage source. The resulting
SAR is therefore tied to that explicitly stated source normalisation.
For a 3-D Hertzian dipole, use normalisation='current_moment' and give
target_amplitude in A m. For a discrete plane wave, use
normalisation='incident_flux' and target_flux in W/m2 when
power flux rather than electric-field amplitude is the required physical
normalisation.
Spatial mass averaging is opt-in. With the default averaging_masses=(),
gprMax writes local cell SAR, absorbed-power density, and per-tag summaries
without running the potentially expensive mass-averaging stage. Supply
(0.001, 0.01) to request the standard 1 g and 10 g results, or any other
positive masses in kg for research applications. Density is constant within
each final tagged cell; only the included volume fraction of a cell changes
at an averaging-cube boundary.
For a one-watt accepted-power result from a named port, use:
scene.add(gprMax.SAR(
frequencies=np.linspace(0.8e9, 1.2e9, 41),
tags=('brain_region',), id='brain_sar_1W',
normalisation='accepted_power', port_id='feed', target_power=1.0,
))
incident_power is also available. target_power is in W for 3-D models
and W/m for invariant 2-D models. Power normalisation currently requires
a rectangular transform window and a physical, valid port-power result at
each requested frequency.
Selected tagged cells that lie in boundary or internal PML regions are excluded automatically because PML loss is not physical material absorption.
SAR may be added to a SubGridHSG in the same way as other
subgrid outputs. Fields are transformed using the fine-grid dt and the
result is written below /subgrids/<subgrid ID>/sar/<output ID>. The
normalising source may be on the main grid or the subgrid; its waveform DFT
uses the timestep of the grid that owns the source. This is useful when a
main-grid plane wave or antenna illuminates finely resolved tagged tissue.
Mass averaging is local to the selected subgrid tag volume, so the complete
tissue region required by an averaging cube should be contained inside the
subgrid working region.
Reduced 2-D TM and TE main-grid models are supported. SAR is evaluated only
on the genuine field plane (invariant index zero for TM and one for TE), and
only the active electric components are transformed. Tag-integrated absorbed
power and mass are written per unit invariant length. Spatial mass averaging
is not yet available in 2-D, so averaging_masses must remain empty for
these models.
See Two-dimensional SAR in lossy dielectric cylinders for analytical TMz and TEz validation against homogeneous lossy-cylinder series over fat-, skin-, and muscle-like material properties.
The default permits output only while the shortest wavelength in any model
material is sampled by at least ten cells. Use spectrum_limit=8 for a
lambda/8 criterion. spectrum_limit='nyquist' is an explicit research
override: it retains the requested frequencies but does not imply spatial
accuracy. Three- and two-dimensional CPU, CUDA, OpenCL, and Metal models are
supported on the main grid. MPI domain-decomposed CPU models and
three-dimensional CPU and CUDA HSG subgrids are also supported. Under MPI, source and
port normalisation and any requested spatial mass averaging are completed
globally on the coordinator, so tag volumes and averaging cubes may cross rank
boundaries. See Absorbed power density and specific absorption rate for the formulation and HDF5 schema.
Radiometric absorption weighting
- class gprMax.user_objects.cmds_output.Radiometry(frequencies, tags=None, waveform_id: str | None = None, id: str = 'radiometry1', target_amplitude: float = 1.0, spectrum_limit=10.0, source_floor_db: float = -40.0, window: str = 'rectangular', normalisation: str = 'waveform', port_id: str | None = None, target_power: float | None = None, target_flux: float | None = None)
Request absorbed-power and radiometric weighting over geometry tags.
The field collection, source normalisation, material-loss formulation, PML exclusion, and mesh-validity policy are identical to
SAR. Density is not required and no mass-based quantity is calculated.normalisationmay be"waveform","current_moment"for a 3-D Hertzian dipole,"incident_flux"for a discrete plane wave, or"incident_power"/"accepted_power"for a physical port. The output includes absorbed-power density and its normalised weighting: absorbed-power fraction density for port power, absorption cross-section density for plane-wave flux, or absorbed power per squared native source amplitude for a portless local source.Only electric absorption contributes to these outputs. Magnetic properties still affect the FDTD fields, but magnetic absorption is not included. Selected magnetic materials outside PML, excluding ideal PMC constraints, trigger a warning; radiometric weights omit any magnetic loss. Lossless permeability alone adds no magnetic heating.
- Parameters
frequencies – Strictly increasing positive frequencies in Hz.
tags – Geometry tag string or iterable of tag strings.
waveform_id – Required for waveform, current-moment, and incident-flux normalisation; unused for port-power normalisation.
id – Unique HDF5 output identifier.
target_amplitude – Positive native source amplitude for waveform or current-moment normalisation.
spectrum_limit – Minimum cells per shortest material wavelength, or
"nyquist"for explicit research output.source_floor_db – Source-support validity threshold in dB.
window –
"rectangular"or"hann".normalisation – One of the modes described above.
port_id – Required for incident- or accepted-power normalisation.
target_power – Required positive W (3-D) or W/m (2-D) for port power.
target_flux – Required positive W/m2 for plane-wave incident flux.
The electric-only absorption limitation and its magnetic-material warning apply to every radiometry normalisation.
Radiometry is the density-independent counterpart of SAR. It uses the
same tagged-cell field transforms and loss calculation, but writes absorbed
power and a source-normalised absorption weighting without requiring
MaterialDensity. A plane-wave absorption cross section is requested with:
scene.add(gprMax.Radiometry(
frequencies=np.linspace(0.5e9, 2e9, 61),
waveform_id='incident', tags=('subsurface_layer',),
id='layer_absorption', normalisation='incident_flux',
target_flux=1.0,
))
For an antenna or local probe with a physical port, omit waveform_id and
normalise to port power:
scene.add(gprMax.Radiometry(
frequencies=np.linspace(0.5e9, 2e9, 61),
tags=('subsurface_layer',), id='probe_weighting',
normalisation='accepted_power', port_id='feed', target_power=1.0,
))
For a portless Hertzian source, current_moment gives an absorption kernel
per squared A m. waveform remains available for every source and retains
that source’s native excitation units. Outputs and their dimensional meaning
are described in Radiometric absorption weighting.
Rational-network S11 and input impedance
- class gprMax.user_objects.cmds_output.NetworkPort(terminal_id: str, reference_impedance: float = 50.0, spectrum_limit=10.0)
Request port quantities for a rational-network terminal.
Port and outputs
Output is explicit: add #network_port: feed or
scene.add(gprMax.NetworkPort(terminal_id='feed')) for terminal feed.
The network and its excitation alone do not request port results. Output is
/ports/feed, or /subgrids/<subgrid ID>/ports/feed for a CPU or CUDA HSG port.
time, Vgenerator, Vtotal and Inetwork describe the generator,
gap voltage (V) and network current (A). Terminal-current spectra remove the
background Yee-gap admittance and are distinct from the external-network
current. frequency, S11, Zin and Yin have independent validity
masks. Reference impedance defaults to 50 Ohms; it does not replace the
physical network admittance.
Keep the NetworkPort object to read port.result.total_voltage,
port.result.s11, port.result.zin and the other result arrays after
solving. Omitting NetworkExcitation leaves a passive measurable load:
its received voltage/current remain useful, but source-normalised S11 is
undefined. Impedance/admittance are available where their own masks permit.
Use python -m gprMax.toolboxes.Plotting.plot_port model.h5 --port feed --save.
See Rational-network port output for the schema, Fixed-topology terminal-source studies for
fixed-network drive studies and Ports, antenna power and NTFF for NTFF use.
NetworkPort requests the output for an existing NetworkTerminal. Its
terminal ID becomes the HDF5 port ID:
network_port = gprMax.NetworkPort(
terminal_id='feed', reference_impedance=50, spectrum_limit=10,
)
scene.add(network_port)
After the solve, network_port.result contains aligned voltage/current
histories and S11, Zin, and Yin spectra. The background Yee-gap
capacitance and conductance are removed from terminal current. Omitting
NetworkExcitation leaves a passive measurable port; it has no meaningful
source-normalised S11 but can still report impedance/admittance where the
response is numerically defined. A port inside a Python API subgrid is written
beneath /subgrids/<subgrid ID>/ports/<terminal ID> and uses that subgrid’s
fine dl and dt.
Source Steps
Receiver Steps
Snapshot
- class gprMax.user_objects.cmds_output.Snapshot(p1: Tuple[float, float, float], p2: Tuple[float, float, float], dl: Tuple[float, float, float], filename: str, fileext: Optional[str] = None, iterations: Optional[int] = None, time: Optional[float] = None, outputs: Optional[List[str]] = None)
- Obtains information about the electromagnetic fields within a volume
of the model at a given time instant.
- p1
tuple required to specify lower left (x,y,z) coordinates of volume of snapshot in metres.
- p2
tuple required to specify upper right (x,y,z) coordinates of volume of snapshot in metres.
- dl
tuple require to specify spatial discretisation of the snapshot in metres.
- filename
string required for name of the file to store snapshot.
- time/iterations
either a float for time or an int for iterations must be specified for the electric-field time level at which the snapshot will be taken. A time is mapped to the nearest full time step. Magnetic fields retain their native half-step staggering.
- fileext
optional string to indicate type for snapshot file, either ‘.vtkhdf’ (default) or ‘.h5’
- outputs
optional list of outputs for receiver. It can be any selection from Ex, Ey, Ez, Hx, Hy, or Hz.
A snapshot added to an HSG subgrid uses that grid’s spatial and temporal discretisation. Its output origin is expressed in global model coordinates.
Receivers can request selected field components, while an array produces regularly spaced receivers over a line, plane, or volume. Source and receiver steps are applied between repeated model runs:
scene.add(gprMax.Rx(
p1=(0.08, 0.05, 0.05), id='surface_rx', outputs=['Ez', 'Hy']
))
scene.add(gprMax.RxArray(
p1=(0.02, 0.10, 0.05), p2=(0.12, 0.10, 0.05),
dl=(0.01, 0, 0),
))
scene.add(gprMax.SrcSteps(p1=(0.002, 0, 0)))
scene.add(gprMax.RxSteps(p1=(0.002, 0, 0)))
scene.add(gprMax.Snapshot(
p1=(0, 0, 0), p2=(0.15, 0.12, 0.10),
dl=(0.002, 0.002, 0.002), time=2e-9,
filename='fields_2ns', fileext='.h5', outputs=['Ez', 'Hy'],
))
A snapshot can also be added to an HSG subgrid. It is sampled on every fine
subgrid time step, uses the subgrid’s spatial discretisation, and records its
origin in the global model coordinate system. The requested time or iteration
is interpreted against the owning subgrid’s dt and iteration count.
In a reduced 2-D model, any requested invariant-axis extent is collapsed to
the single genuine field plane: index zero for TM or index one for TE.
Snapshot values are evaluated at the regular output-cell centres written to
the file. Coarse dl uses linear interpolation of native Yee samples, not
volume averaging; native-cell spacing preserves the original arithmetic.
Non-dividing interior ROIs keep ceil((p2-p1)/dl) output cells. Construction
rejects a final regular cell whose centre or interpolation stencil requires
samples outside the physical Yee grid. Unlike older versions, this does not
silently clip or enlarge p2 or alter live-axis dl. Choose a smaller
extent or spacing instead. MPI exchanges only the required native samples at
snapshot iterations; ranks with no output cells still participate.
The snapshot time is rounded to the nearest full electric-field time
level \(n\Delta t\) (halfway values round to the earlier step), while
iterations=n selects the same zero-based level directly. Snapshot electric
fields are at \(n\Delta t\) and magnetic fields retain their native Yee
stagger at \((n-1/2)\Delta t\); there is no temporal averaging. Valid
indices are 0 <= n < the owning grid’s number of iterations. This temporal
definition is separate from the existing spatial collocation of field
components in a snapshot cell.
Reusable NTFF integration surface
- class gprMax.user_objects.cmds_output.NTFFSurface(p1, p2, id: str, origin=None, omit_faces=())
Define a reusable Yee-aligned field-transformation surface.
The reusable Python interface has a one-to-one mapping to the supported NTFF hash commands:
Python class |
Hash command |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The mapping covers the reusable operations and their normal options. The
Python API also exposes advanced keyword arguments that cannot be entered
positionally in a hash command: NTFFSurface.origin, and
save_surface_dft and plane_wave_index on either frequency-transform
class. Hash
commands use the default surface centre, save the surface DFT, and associate
an enclosed plane wave automatically.
The KSIR* classes require a closed NTFFSurface; this rule is independent
of whether an eigenmode source is present. Traditionally a real guide extends
through the domain PML and the crossed Huygens face is omitted, which makes
that open surface unsuitable for KSIR. A VirtualWaveguide moves the matched
continuation outside the main domain, allowing the eigenmode-fed antenna to be
enclosed by either a closed KSIR or closed equivalent-current surface.
NTFFSurface(omit_faces=('x0', 'xmax')) creates an open frequency-domain
Huygens surface. omit_faces accepts one to five distinct Cartesian face
names; at least one of the six faces must remain active. A feed crossing an
opening continues uniformly into its PML, with the impressed source plane
outside the Huygens volume. KSIR and ordinary transient equivalent-current
outputs reject omitted physical faces. The exception is a direct layered-time
transform whose one omitted face coincides exactly with its declared terminal
PEC plane. This is the grounded-slab construction described in
Near-to-far-field transformations.
A PEC-backed substrate can be declared through the same background class;
pec is the terminal entry and the adjacent interface is its physical
coordinate:
scene.add(gprMax.NTFFLayeredBackground(
id='grounded', axis='z',
materials=('free_space', 'substrate', 'pec'),
interfaces=(0.0, -0.002),
))
This declaration does not build the corresponding substrate or PEC geometry. Only directions in the open hemisphere may be requested.
NTFF definitions are main-grid objects, but their notional closed integration surface may enclose complete HSG subgrids. A surface must not touch or cut an HSG outer coupling surface: overlapping regions require the NTFF surface to strictly enclose that outer surface. Sources and scatterers inside the subgrid then contribute through the normal HSG field exchange. A disjoint subgrid is permitted. NTFF surfaces cannot be defined inside a subgrid.
The same interface is available with MPI domain decomposition. Surface patches are distributed between ranks and use the existing field halos, while the completed results retain the same HDF5 schema as a serial run. MPI NTFF does not introduce a surface collective during each FDTD iteration; accumulated time histories or frequency-domain phasors are combined once at finalisation. Geometry-fixed reuse remains unsupported.
The following example reuses one surface for an exact time-domain point and a frequency-domain radiation pattern. Python keyword arguments replace the positional optional parameters used by the equivalent hash commands.
scene.add(gprMax.NTFFSurface(
p1=(0.03, 0.03, 0.03),
p2=(0.07, 0.07, 0.07),
id='radiation_surface',
))
scene.add(gprMax.KSIRTimeRx(
position=(0.12, 0.05, 0.05),
surface_id='radiation_surface',
id='transient',
outputs=('Ez',),
time_origin='first_arrival',
))
scene.add(gprMax.KSIRFrequencyTransform(
surface_id='radiation_surface',
id='antenna_band',
frequencies=(0.8e9, 1.0e9, 1.2e9),
window='hann',
))
scene.add(gprMax.KSIRFarFieldArray(
theta_start=0,
theta_stop=180,
theta_step=5,
phi_start=0,
phi_stop=360,
phi_step=5,
transform_id='antenna_band',
id='pattern',
outputs=('Etheta', 'Ephi', 'radiation_intensity'),
))
For a completed time receiver, result.point_times(q) and
result.point_field(output, q) return only the interval supported by every
surface patch. point_raw_times and point_raw_field deliberately expose
the additional partial retarded tail for research use. Check
result.terminal_decay_ok[q]; a false value means that the FDTD time window
should be increased.
KSIR frequency transform
- class gprMax.user_objects.cmds_output.KSIRFrequencyTransform(surface_id: str, id: str, frequencies, window: str = 'rectangular', save_surface_dft: bool = True, plane_wave_index: Optional[int] = None)
Declare frequencies and a window for one reusable NTFF surface.
KSIR antenna-port association
- class gprMax.user_objects.cmds_output.KSIRAntennaPorts(transform_id, port_ids)
Associate all physical antenna ports with one KSIR transform.
- Parameters
transform_id – ID of a rectangular-window
KSIRFrequencyTransform.port_ids – IDs of every physical antenna port. Voltage-source IDs come directly from the source (explicit or automatic). Transmission-line and magnetic-frill sources use their automatic
tlNandfrillNIDs. Rational-network ports use their terminal IDs and must be explicitly requested withNetworkPort. A port on a subgrid is referenced as<subgrid ID>/<local port ID>. Active eigenmode sources cannot use this conventional terminal gain-normalisation path; useNTFFAntennaPortsinstead. This restriction does not prohibit raw KSIR field reconstruction on a compatible closed surface around a virtual-guide-fed antenna.
The complete set is required for an unambiguous coherent accepted-power balance. A source with zero waveform amplitude is still a terminated port and must be included.
The association is needed only for gain and efficiency. It must name every
physical conventional port, including a zero-amplitude source that acts as
a termination and explicitly monitored rational-network terminals.
Main-grid port IDs are used directly. A subgrid port is qualified by its
subgrid ID, for example fine_grid/feed, fine_grid/tl1, or
fine_grid/frill1. Its voltage and current spectra are transformed with the
owning subgrid’s finer time step.
For voltage sources, use the source’s id (or its automatic portN ID); automatic
transmission-line and magnetic-frill IDs are tl1, … and frill1, …
respectively. Rational-network ports use their terminal IDs. For active modal
sources use an equivalent-current transform with NTFFAntennaPorts, not
this conventional KSIR gain-normalisation path. Raw KSIR fields on a compatible
closed surface remain a separate capability. See Ports, antenna power and NTFF.
For a conventional two-terminal antenna:
scene.add(gprMax.KSIRFrequencyTransform(
surface_id='radiation_surface',
id='antenna_band',
frequencies=(0.8e9, 1.0e9, 1.2e9),
window='rectangular',
))
scene.add(gprMax.KSIRAntennaPorts(
transform_id='antenna_band',
port_ids=('element1', 'element2'),
))
scene.add(gprMax.KSIRFarFieldArray(
theta_start=0,
theta_stop=180,
theta_step=2,
phi_start=0,
phi_stop=360,
phi_step=2,
transform_id='antenna_band',
id='array_pattern',
outputs=(
'directivity_dbi',
'gain_dbi',
'realized_gain_dbi',
'radiation_efficiency',
'total_efficiency',
),
))
The same surface may independently supply conventional equivalent-current far fields. For example:
scene.add(gprMax.NTFFFrequencyTransform(
surface_id='radiation_surface',
id='current_band',
frequencies=(0.8e9, 1.0e9, 1.2e9),
window='hann',
))
scene.add(gprMax.NTFFFarFieldArray(
theta_start=0,
theta_stop=180,
theta_step=5,
phi_start=0,
phi_stop=360,
phi_step=5,
transform_id='current_band',
id='current_pattern',
outputs=('Etheta', 'Ephi', 'directivity_dbi'),
))
scene.add(gprMax.NTFFTimeFarField(
theta=90,
phi=0,
surface_id='radiation_surface',
id='current_transient',
outputs=('Etheta', 'Ephi'),
))
The full sphere needed to normalise directivity and efficiency is generated
internally. The directions stored for array_pattern remain exactly those
requested above. Gain uses the coherent net accepted power of the complete
port set, so amplitudes and delays applied to the source waveforms can model
array steering. For broadband pulses, a time delay represents true-time-delay
steering; a fixed phase shift is frequency-specific.
KSIR exact time-domain receivers
- class gprMax.user_objects.cmds_output.KSIRTimeRx(position, surface_id: str, id: Optional[str] = None, outputs=None, time_origin: str = 'simulation')
Request exact advanced-time KSIR fields at Cartesian point(s).
- class gprMax.user_objects.cmds_output.KSIRTimeRxSpherical(r, theta, phi, surface_id, id=None, outputs=None, time_origin='simulation')
Request exact advanced-time KSIR fields at spherical coordinate(s).
- class gprMax.user_objects.cmds_output.KSIRTimeRxArray(p1, p2, dl, surface_id, id=None, outputs=None, time_origin='simulation')
Request exact time-domain fields on a Cartesian point array.
KSIR exact frequency-domain receivers
- class gprMax.user_objects.cmds_output.KSIRFrequencyRx(position, transform_id, id=None, outputs=None)
Request exact finite-distance frequency-domain Cartesian fields.
- class gprMax.user_objects.cmds_output.KSIRFrequencyRxSpherical(r, theta, phi, transform_id, id=None, outputs=None)
Request exact finite-distance frequency-domain spherical fields.
- class gprMax.user_objects.cmds_output.KSIRFrequencyRxArray(p1, p2, dl, transform_id, id=None, outputs=None)
Request exact frequency-domain fields on a Cartesian point array.
KSIR range-normalized far fields
- class gprMax.user_objects.cmds_output.KSIRFarField(theta, phi, transform_id, id=None, outputs=None)
Request range-normalized far fields in paired spherical directions.
In addition to Cartesian and spherical field components,
outputsmay contain radiation intensity, directivity, gain, realized gain, radiation or total efficiency, and RCS. Directivity and efficiency use an internal full-sphere quadrature even when only a cut is requested. Gain and efficiency require aKSIRAntennaPortsassociation.
- class gprMax.user_objects.cmds_output.KSIRFarFieldArray(theta_start, theta_stop, theta_step, phi_start, phi_stop, phi_step, transform_id, id=None, outputs=None)
Request a theta/phi product grid of range-normalized far fields.
The spherical receiver radius is explicit and produces an exact physical
finite-distance field. KSIRFarField deliberately has no radius and
returns r * exp(+j*k*r) * field. All spherical angles use theta from
+z and phi from +x towards +y. A surface face that coincides with
a declared PEC or PMC symmetry boundary is completed automatically by image
theory.
Equivalent-current far fields
- class gprMax.user_objects.cmds_output.NTFFFrequencyTransform(surface_id: str, id: str, frequencies, window: str = 'rectangular', save_surface_dft: bool = True, plane_wave_index: Optional[int] = None)
Declare a conventional equivalent-current frequency transform.
- class gprMax.user_objects.cmds_output.NTFFLayeredBackground(id: str, axis: str, materials, interfaces=())
Declare a planar material stack for layered equivalent-current NTFF.
Materials are ordered from the positive-axis side to the negative-axis side. The built-in
pecidentifier may occur once, as the first or last entry, to declare a perfect short-circuit termination at the adjacent interface. It is analytical propagation metadata and does not build the corresponding PEC FDTD geometry.
- class gprMax.user_objects.cmds_output.NTFFLayeredFrequencyTransform(surface_id: str, id: str, background_id: str, frequencies, window: str = 'rectangular', save_surface_dft: bool = True, plane_wave_index: Optional[int] = None)
Declare an equivalent-current transform for a planar layered background.
- class gprMax.user_objects.cmds_output.NTFFLayeredTimeTransform(surface_id: str, id: str, background_id: str, impulse_tolerance: float = 1e-10, max_impulses: int = 100000)
Declare a direct time-domain transform for a lossless planar stack.
The transform uses the delayed TE/TM impulse-train formulation developed by Capoglu. Conductive, dispersive, evanescent, and exact-grazing cases must use
NTFFLayeredFrequencyTransform.
- class gprMax.user_objects.cmds_output.NTFFFarField(theta, phi, transform_id, id=None, outputs=None)
Request equivalent-current range-normalized far fields.
A planar-layered transform additionally accepts the grouped outputs
"exterior_power","exterior_maximum", and"exterior_efficiency". They store positive- and negative-stack-axis radiation summaries without retaining the temporary full-sphere fields. Exterior efficiency requires anNTFFAntennaPortsassociation; exterior power and conventional directivity do not.
- class gprMax.user_objects.cmds_output.NTFFFarFieldArray(theta_start, theta_stop, theta_step, phi_start, phi_stop, phi_step, transform_id, id=None, outputs=None)
Request an equivalent-current theta/phi far-field product grid.
- class gprMax.user_objects.cmds_output.NTFFAntennaPorts(transform_id, port_ids)
Associate all physical antenna ports with an equivalent-current transform.
In addition to conventional terminal ports, every EigenmodePort uses
portNfor its explicit port index, whether driven or passive. Every transform frequency must be present in each associated modal port’s direct-DFT bins; the modal DFT grid may contain additional bins.
These classes provide the conventional Love-current frequency transform and share the KSIR far-field output and antenna-metric definitions. They do not provide finite-distance receivers. See Near-to-far-field transformations for the surface-current equations and engineering phasor convention.
Advanced NTFF utilities
The following low-level API utilities support specialised post-processing
and research workflows. They are not scene objects and should not be passed
to Scene.add.
- class gprMax.SymmetryCompletion(faces: Optional[Tuple[str, ...]] = None)
Request exact completion from resolved gprMax PEC/PMC boundaries.
If faces is omitted, every declared symmetry boundary touched by the logical KSIR box is used.
- Parameters
faces – optional tuple containing any of
x0,xmax,y0,ymax,z0, andzmax. If omitted, use all compatible symmetry faces touched by the logical integration box.
- class gprMax.ExperimentalMask(omit_faces: Tuple[str, ...])
Deliberately omit complete physical faces from the KSIR integral.
This is a research diagnostic, not a closed-surface transformation. Omitting a face generally violates the exact KSIR representation and can produce non-physical fields unless the user supplies an independently justified closure.
- Parameters
omit_faces – tuple containing one to five distinct faces from
x0,xmax,y0,ymax,z0, andzmax.
- gprMax.evaluate_saved_surface_dft(filename: pathlib.Path | str, monitor_name: str, theta: ArrayLike, phi: ArrayLike, *, origin: Optional[ArrayLike] = None) KSIRSavedFarField
Evaluate new directions from a saved production KSIR surface DFT.
- Parameters
filename – model HDF5 output containing a saved KSIR surface DFT.
monitor_name – frequency-transform identifier below the
/ntffgroup.theta – one-dimensional polar-angle values in degrees.
phi – one-dimensional azimuthal-angle values in degrees.
origin – optional Cartesian phase-reference origin in metres. If omitted, use the origin stored with the surface.
- Returns
A
KSIRSavedFarFieldevaluated on the Cartesian product ofthetaandphiwithout rerunning FDTD.
- gprMax.spherical_observation_points(origin: ArrayLike, radius: ArrayLike, theta: ArrayLike, phi: ArrayLike, *, degrees: bool = False) NDArray[floating]
Create Cartesian KSIR observation points from spherical coordinates.
thetais measured from +z andphifrom +x toward +y. Radius and angles use NumPy broadcasting; the broadcast result is flattened to the(npoints, 3)array accepted by the exact-point KSIR evaluator. For an angular product grid, pass (for example)theta[:, None]andphi[None, :].- Parameters
origin – Cartesian sphere origin
(x, y, z)in metres.radius – positive radius value or broadcastable array in metres.
theta – polar angle value or broadcastable array.
phi – azimuthal angle value or broadcastable array.
degrees – interpret angles in degrees rather than radians.
- Returns
Contiguous Cartesian point array with shape
(npoints, 3).
SymmetryCompletion requests an exact image-theory completion at declared
PEC or PMC symmetry boundaries. ExperimentalMask deliberately makes a
KSIR surface mathematically open; it is provided for controlled research
experiments and generally does not produce a physical field without a
separately justified closure. evaluate_saved_surface_dft evaluates a
compatible saved surface spectrum after a run, while
spherical_observation_points constructs Cartesian exact-field receiver
locations from spherical coordinates.
A layered transform reuses the same far-field request classes. For example, air above a finite dielectric layer and a lower dielectric half-space can be declared independently of the geometry objects which build those layers:
scene.add(gprMax.NTFFLayeredBackground(
id='ground',
axis='z',
materials=('free_space', 'dry_soil', 'wet_soil'),
interfaces=(0.0, -0.1),
))
scene.add(gprMax.NTFFLayeredFrequencyTransform(
surface_id='radiation_surface',
id='ground_band',
background_id='ground',
frequencies=(0.8e9, 1.0e9, 1.2e9),
window='rectangular',
))
scene.add(gprMax.NTFFFarField(
theta=30,
phi=0,
transform_id='ground_band',
id='upper_pattern',
outputs=(
'Etheta',
'Ephi',
'directivity_dbi',
'exterior_power',
'exterior_maximum',
),
))
The two exterior materials must be lossless and an explicitly requested direction must not be exactly grazing to the layer normal. Internal layers may be conductive or electrically dispersive. See Near-to-far-field transformations for the TE/TM transmission-line formulation. Far-field and antenna metrics support different lossless exterior materials; coherent array-codebook synthesis currently requires equal, frequency-independent exterior impedances.
The grouped exterior_power output stores the radiated power and fraction
in each positive- and negative-axis exterior. exterior_maximum stores the
maximum radiation intensity, conventionally full-sphere-normalised
directivity, and its direction in each exterior. These two requests do not
require a port. exterior_efficiency additionally stores each exterior’s
accepted- and incident-power-normalised coupling efficiency and maximum gain;
it therefore requires NTFFAntennaPorts, every physical port, and a
rectangular transform window. For example:
scene.add(gprMax.NTFFAntennaPorts(
transform_id='ground_band',
port_ids=('feed',),
))
pattern = gprMax.NTFFFarFieldArray(
theta_start=1,
theta_stop=179,
theta_step=2,
phi_start=0,
phi_stop=358,
phi_step=2,
transform_id='ground_band',
id='ground_pattern',
outputs=(
'Etheta',
'Ephi',
'gain_dbi',
'realized_gain_dbi',
'exterior_power',
'exterior_efficiency',
'exterior_maximum',
),
)
scene.add(pattern)
Here the layered transform must use window='rectangular' because the
second request is normalised by the port spectra. The exact grazing direction
is omitted from this example; it is singular in the layered far-zone
representation.
After the run, the same summaries are available without reopening the HDF5
file through pattern.result.radiation_metrics.exterior. Its arrays use
region order (positive_axis, negative_axis) and then frequency; the HDF5
writer presents those two rows as named groups.
Time-domain equivalent-current far fields
- class gprMax.user_objects.cmds_output.NTFFTimeFarField(theta, phi, surface_id, id=None, outputs=None)
Request 1997 equivalent-current time-domain far fields.
- class gprMax.user_objects.cmds_output.NTFFTimeFarFieldArray(theta_start, theta_stop, theta_step, phi_start, phi_stop, phi_step, surface_id, id=None, outputs=None)
Request a theta/phi grid of 1997 time-domain far fields.
- class gprMax.user_objects.cmds_output.NTFFLayeredTimeFarField(theta, phi, transform_id, id=None, outputs=None)
Request direct time-domain far fields from a layered time transform.
- class gprMax.user_objects.cmds_output.NTFFLayeredTimeFarFieldArray(theta_start, theta_stop, theta_step, phi_start, phi_stop, phi_step, transform_id, id=None, outputs=None)
Request a theta/phi product grid from a layered time transform.
NTFFTimeFarField and NTFFTimeFarFieldArray compute homogeneous
time-domain equivalent-current far fields on the CPU, CUDA, OpenCL, and Metal
solvers. The calculation includes the time-staggering modification of
Giannopoulos et al. [GIAFF1997], described in
Time-domain far field. Their times are reduced times for
range-normalized far fields, and only samples supported by every surface
patch are returned.
NTFFLayeredTimeTransform and its request classes replace homogeneous
propagation by the direct TE/TM impulse responses of a lossless planar stack
[CAP2007]. They reuse NTFFLayeredBackground. Every layer must be
positive, lossless, and nondispersive, and each requested direction must be
propagating in every layer and non-grazing. CPU and MPI execution use a
Cython/OpenMP accumulation kernel; CUDA, OpenCL, and Metal use device-resident
gather and sparse-deposition kernels. Use NTFFLayeredFrequencyTransform
for conductive, dispersive, or evanescent cases.
For example:
scene.add(gprMax.NTFFLayeredTimeTransform(
surface_id='radiation_surface',
id='ground_transient',
background_id='ground',
))
scene.add(gprMax.NTFFLayeredTimeFarFieldArray(
theta_start=5,
theta_stop=175,
theta_step=5,
phi_start=0,
phi_stop=355,
phi_step=5,
transform_id='ground_transient',
id='transient_pattern',
outputs=('Etheta', 'Ephi'),
))
Subgrid
- class gprMax.SubGridHSG(p1=None, p2=None, ratio=3, id='', is_os_sep=3, pml_separation=4, subgrid_pml_thickness=6, interpolation=1, filter=True)
Huygens Surface subgridding (HSG) user object.
- p1
list of the position of the lower left corner of the Inner Surface (x, y, z) in the main grid.
- p2
list of the position of the upper right corner of the Inner Surface (x, y, z) in the main grid.
- ratio
int of the ratio of the main grid spatial step to the sub-grid spatial step. Must be an odd integer.
ratio=1selects an equal-resolution embedded region: field values are transferred directly, without temporal or spatial interpolation, filtering, or a subgrid-boundary PML. It inherits the precision of the main CPU or CUDA grid.
- id
required nonempty string identifier, unique within the Scene. Path separators, NUL, ‘.’ and ‘..’ are not allowed.
- is_os_sep
int for the number of main grid cells between the Inner Surface and the Outer Surface. Defaults to 3.
- pml_separation
retained for API compatibility, but the HSG formulation fixes the number of sub-grid cells between the Outer Surface and the PML at
ratio // 2 + 2. Any supplied value is therefore ignored. Using a different value is experimental and requires changing the formulation.
- subgrid_pml_thickness
int for the thickness of the PML on each of the 6 sides of the sub-grid. Defaults to 6. Ignored when
ratio=1.
- interpolation
int for the degree of the interpolation scheme used for spatial interpolation of the fields at the Inner Surface on CPU and CUDA. FITPACK spline degrees 1–5 are supported when each coarse precursor axis has more samples than the degree. Defaults to linear (1), the standard HSG choice. Higher degrees are experimental; matching the CPU does not guarantee stability. Ignored when
ratio=1, where transfer is direct.
- filter
boolean to turn on the 3-pole filter. Increases numerical stability. Defaults to True. Ignored when
ratio=1.
A subgrid is added to the main scene, but its materials and geometry are added
to the subgrid object. With autotranslate=True these objects can use main
grid coordinates. Refining subgrids support the double-precision CPU and CUDA
solvers. OpenCL, Metal, and distributed MPI subgrid execution are not supported.
Pass subgrid=True even for a geometry-only preview; a Scene containing
subgrids without that flag is rejected before model construction. Every subgrid
must have a nonempty id unique within its Scene. IDs cannot contain path
separators or NUL, or be . or .., because they identify HDF5 groups.
ratio=1 selects an equal-resolution embedded region. This is exposed
through SubGridHSG to avoid a second, overlapping object API, but it does
not refine space or time: values are transferred directly on the shared Yee
lattice, the subgrid-boundary PML and filter are disabled, and no spatial or
temporal interpolation is performed. It inherits cpu_precision or
gpu_precision from the main CPU or CUDA grid respectively. This mode is
useful, for example, for confining dispersive material
storage and updates to a local part of a larger model.
Only the auxiliary PML around the embedded region is disabled at ratio=1.
Explicitly added PMLSlab absorbers remain active at each local time step.
For refining grids, interpolation=1 (linear) and filter=True are the
standard defaults. The API also accepts FITPACK spline degrees 2–5 on both CPU
and CUDA, provided each coarse precursor axis contains more samples than the
chosen degree. CUDA uses the same spline boundary behaviour as CPU and keeps
field interpolation on the device. Higher degrees are experimental: numerical
parity does not establish stability or improve accuracy for every model. Both
options are ignored for ratio=1.
Note
The HSG formulation fixes pml_separation at ratio // 2 + 2. The
constructor retains the argument for API compatibility, but any supplied
value is intentionally ignored. Changing this separation is experimental
and requires modifying the formulation in the source code.
subgrid = gprMax.SubGridHSG(
p1=(0.06, 0.04, 0.03), p2=(0.12, 0.10, 0.09),
ratio=3, id='fine_grid',
)
scene.add(subgrid)
subgrid.add(gprMax.Material(
er=4, se=0, mr=1, sm=0, id='subgrid_material'
))
subgrid.add(gprMax.Sphere(
p1=(0.09, 0.07, 0.06), r=0.01,
material_id='subgrid_material',
))
gprMax.run(
scenes=[scene], n=1, outputfile='subgrid_model',
subgrid=True, autotranslate=True,
)
PML functions
The default behaviour for the absorbing boundary conditions (ABC) is first order Complex Frequency Shifted (CFS) Perfectly Matched Layers (PML), with thicknesses of 10 cells on each of the six sides of the model domain. The PML can be customised using the following commands:
PML Formulation
- class gprMax.user_objects.cmds_singleuse.PMLFormulation(formulation: str, id: Optional[str] = None)
Set the formulation of the PMLs.
Current options are to use the Higher Order RIPML (HORIPML) - https://doi.org/10.1109/TAP.2011.2180344, or Multipole RIPML (MRIPML) - https://doi.org/10.1109/TAP.2018.2823864.
- formulation
Either ‘HORIPML’ or ‘MRIPML’.
- Type
str
- id
Reusable profile identifier. If omitted, set the global formulation used by domain PMLs and unqualified slabs.
- Type
str, optional
PML Thickness
- class gprMax.user_objects.cmds_singleuse.PMLThickness(thickness: Union[int, Tuple[int, int, int, int, int, int]])
Set the thickness of the PMLs.
The thickness can be set globally, or individually for each of the six sides of the model domain. Either thickness must be set, or all of x0, y0, z0, xmax, ymax, zmax.
- thickness
Thickness of the PML on all 6 sides or individual sides of the model domain.
- Type
int | Tuple[int]
For example, select the multipole formulation and set the thickness of each
domain face independently, in the order x0, y0, z0, xmax, ymax, zmax:
scene.add(gprMax.PMLFormulation(formulation='MRIPML'))
scene.add(gprMax.PMLThickness(thickness=(12, 12, 10, 12, 12, 10)))
Symmetry Boundary
- class gprMax.user_objects.cmds_multiuse.SymmetryBoundary(**kwargs)
Sets a PEC or PMC symmetry boundary condition on a model-domain face.
The selected boundary replaces the PML on that face. A PEC boundary forces the tangential electric-field component IDs to the built-in PEC material during grid construction. A PMC boundary uses an image-theory ghost-node update for the on-wall tangential electric fields.
PEC and PMC boundaries, including PMC boundaries in dispersive models, are supported by the CPU, CUDA, OpenCL, Metal, and domain-decomposed MPI CPU solvers. Symmetry boundaries are not supported in 2D mode or on a subgrid, although they may be used on the main grid of a model that contains subgrids.
- face
One of
x0,y0,z0,xmax,ymax, orzmax.
- type
Either
pecorpmc.
scene.add(gprMax.SymmetryBoundary(face='x0', type='pmc'))
Domain-decomposed MPI CPU models support the same PEC and PMC boundaries. Only ranks touching a selected global face construct and update it, and domain-edge corrections are not applied at internal MPI seams.
PML Properties
- class gprMax.user_objects.cmds_singleuse.PMLProps(formulation: Optional[str] = None, thickness: Optional[int] = None, x0: Optional[int] = None, y0: Optional[int] = None, z0: Optional[int] = None, xmax: Optional[int] = None, ymax: Optional[int] = None, zmax: Optional[int] = None)
Specify the formulation and thickness of the PMLs.
A PML can be set on each of the six sides of the model domain. Current options are to use the Higher Order RIPML (HORIPML) - https://doi.org/10.1109/TAP.2011.2180344, or Multipole RIPML (MRIPML) - https://doi.org/10.1109/TAP.2018.2823864.
Deprecated: PMLProps is deprecated and may be removed in future releases of gprMax. Use the new PMLFormulation and PMLThickness user objects instead.
- pml_formulation
User object to set the PML formulation.
- Type
- pml_thickness
User object to set the PML thickness.
- Type
Warning
PMLProps is retained for compatibility with older Python models. New
models should use PMLFormulation, PMLThickness, and, when detailed
coefficient control is needed, PMLCFS.
PML CFS
Allows you control of the specific parameters that are used to build each order of the PML. Up to a second order PML can currently be specified, i.e. by using two PMLCFS commands.
- class gprMax.user_objects.cmds_multiuse.PMLCFS(**kwargs)
- Controls parameters that are used to build each order of PML. Default
values are set in pml.py
- alphascalingprofile
string required for type of scaling to use for CFS alpha parameter.
- alphascalingdirection
string required for direction of scaling to use for CFS alpha parameter.
- alphamin
float required for minimum value for the CFS alpha parameter.
- alphamax
float required for maximum value for the CFS alpha parameter.
- kappascalingprofile
string required for type of scaling to use for CFS kappa parameter.
- kappascalingdirection
string required for direction of scaling to use for CFS kappa parameter.
- kappamin
float required for minimum value for the CFS kappa parameter.
- kappamax
float required for maximum value for the CFS kappa parameter.
- sigmascalingprofile
string required for type of scaling to use for CFS sigma parameter.
- sigmascalingdirection
string required for direction of scaling to use for CFS sigma parameter.
- sigmamin
float required for minimum value for the CFS sigma parameter.
- sigmamax
float required for maximum value for the CFS sigma parameter.
- profile_id
optional reusable PML-profile identifier. If omitted, the parameters modify the global domain-PML configuration.
For example, the following explicitly requests the coefficient profiles used by the default first-order PML:
scene.add(gprMax.PMLCFS(
alphascalingprofile='constant',
alphascalingdirection='forward',
alphamin=0, alphamax=0,
kappascalingprofile='constant',
kappascalingdirection='forward',
kappamin=1, kappamax=1,
sigmascalingprofile='quartic',
sigmascalingdirection='forward',
sigmamin=0, sigmamax=None,
))
The CFS values (which are internally specified) used for the default standard first order PML are:
alphascalingprofile = 'constant'alphascalingdirection = 'forward'alphamin = 0alphamax = 0kappascalingprofile = 'constant'kappascalingdirection = 'forward'kappamin = 1kappamax = 1sigmascalingprofile = 'quartic'sigmascalingdirection = 'forward'sigmamin = 0sigmamax = None
Note
The parameters will be applied to all slabs of the PML that are switched on.
Using
Nonefor the maximum value of \(\sigma\) forces gprMax to calculate it internally based on the relative permittivity and permeability of the underlying materials in the model.forwarddirection implies a minimum parameter value at the inner boundary of the PML and maximum parameter value at the edge of the computational domain,reverseis the opposite.
Selecting a stable second-order HORIPML profile
Duplicating two unshifted first-order HORIPML factors can create an unstable absorber. Coefficient construction rejects the demonstrated negative-real product-stretch profiles and identifies the slab/profile, electric or magnetic sample, and parameters. Reducing the timestep does not cure that profile instability.
Use one CFS factor, or repair the investigated unit-kappa configuration with
an unshifted first factor by matching the second alpha grading to
1.1 * sigma1. Match both polynomial order and direction at every electric
and magnetic sample. Alpha and sigma use the same units in these commands.
This recipe is specific to that configuration, not arbitrary custom profiles.
The full analytical condition and the tested 20,000-step cases are in
Second-order HORIPML profile guard.
The check covers boundary, internal, and virtual-guide PMLs, including
terminal samples and the global profile before partitioning. Explicit
sigmamax=0 remains zero; only None requests automatic conductivity.
Passing the check excludes the demonstrated failure mechanism, not every
material, geometry, or mesh instability. The product argument is specific
to HORIPML and must not be applied to MRIPML.
Reusable profiles and internal PML slabs
An optional id on PMLFormulation defines a reusable local profile
instead of changing the global PML formulation. One or two PMLCFS
objects may be associated with it through profile_id. A named formulation
without named CFS terms uses the default first-order CFS parameters.
- class gprMax.user_objects.cmds_multiuse.PMLSlab(**kwargs)
Place an experimental one-axis RIPML slab inside a grid.
p1andp2bound a rectangular region.maximum_faceselects the local face at which complex stretching is greatest; the profile reduces to zero towards the opposite face. For example,x0has its maximum atp1.xand opens towards increasing x. Unlike a domain-boundary PML, the slab is a correction applied to the existing geometry. By default, gprMax creates PEC plates on its four transverse faces and maximum-stretch face; faces coincident with the model boundary are omitted. The zero-stretch entrance remains open. Setbuild_pec=Falseto provide a custom or deliberately open enclosure. Exposed faces are then reported as warnings; incomplete enclosures have no stability guarantee. A slab added to an HSG subgrid must lie wholly within its working region. Domain-decomposed MPI CPU models may partition a slab normally or transversely; every rank stores only its local PML history while retaining the complete global CFS profile.- p1
lower physical
(x, y, z)corner of the slab.
- p2
upper physical
(x, y, z)corner of the slab.
- maximum_face
face at maximum stretching:
x0,xmax,y0,ymax,z0, orzmax.
- profile_id
optional reusable PML profile. If omitted, the global PML formulation and CFS parameters are used.
- build_pec
create the five enclosing PEC plates. The default is
True.
- id
optional unique slab identifier. If omitted, gprMax generates one.
For example, a local MRIPML load can be placed inside a PEC rectangular guide:
scene.add(gprMax.PMLFormulation(formulation='MRIPML', id='port_load'))
scene.add(gprMax.PMLSlab(
p1=(0.005, 0.010, 0.010),
p2=(0.015, 0.020, 0.020),
maximum_face='x0',
profile_id='port_load',
id='feed_absorber', # optional API-only label
build_pec=True, # default: generate the PEC enclosure
))
The automatically generated PEC enclosure is applied after user geometry but
before component averaging and PML coefficient generation. Four transverse
walls and the maximum-stretch backing plate are generated unless a face is
already on a model boundary; the opposite, zero-stretch face is the open
entrance. Set build_pec=False for manually constructed or deliberately
open experiments. gprMax then warns about exposed faces rather than rejecting
the model. Such incomplete enclosures have no stability guarantee and require
case-specific long-duration testing. The material cross-section must be
invariant through the slab.
When id is omitted, gprMax assigns internal_pml_1,
internal_pml_2, and so on. Internal slabs support the CPU, CUDA, OpenCL,
and Metal solvers on the main 3D grid. A slab may also be added to an HSG
subgrid, where it uses the CPU or CUDA solver and the local-grid update cycle,
including equal-resolution regions with ratio=1. A
subgrid-owned slab must lie wholly within the working region: overlap with its
HSG coupling or auxiliary-PML regions is rejected.
Domain-decomposed MPI CPU models are supported. The user declaration remains in global coordinates and may cross normal or transverse rank boundaries. Each participating rank allocates only its local PML history arrays, but its coefficient slice is taken from the complete global CFS profile so a partition does not restart the grading. The ordinary field-halo exchanges join these local corrections; no additional slab-specific communication is required per timestep. Automatic PEC enclosure, collective material-extrusion checks, custom profiles, and use as a replacement for a disabled boundary PML retain their serial behaviour.