Skip to content

Simulation

Simulation is the primary high-level builder in rfx. It owns the domain, boundary conditions, geometry, sources, probes, ports, and the time-domain run.

from rfx import Simulation
sim = Simulation(
freq_max=4e9,
domain=(0.08, 0.06, 0.025),
boundary="cpml",
cpml_layers=16,
dx=1e-3,
mode="3d",
)

Key constructor arguments:

ArgumentMeaningNotes
freq_maxhighest frequency of interestdrives mesh and timestep selection
domain(x, y, z) domain size in metersrequired unless derived by automation
boundaryboundary type"cpml", "pec", "upml", or a per-face BoundarySpec; the public examples center on cpml
cpml_layersabsorber thicknessSimulation default is 16
pec_facesface-based PEC truncationdeprecated and scheduled for removal in rfx v2.0; encode PEC faces in a BoundarySpec instead. Not a substitute for finite antenna ground-plane metal
dxbase lateral cell sizemay be inferred by automation
dz_profile / dx_profile / dy_profilenon-uniform cell profilesworkflow helper for thin-substrate or graded meshes
solversolver familypublic examples and documented RF calculations use Yee

Ground-plane rule: if the structure needs a finite ground plane, model it as geometry. Do not use PEC face truncation (pec_faces, or a pec face in a BoundarySpec) as a substitute for antenna ground-plane metal.

MethodPurposePublic note
add(shape, material=...)fill geometry with a named materialgeometry should stay explicit in public examples
add_material(...)register a named materialuse this for custom dielectric / conductive / dispersive media
add_source(...)inject a soft point sourcepreferred for ringdown and Harminv work
add_port(...)add a lumped or wire portuse for impedance-normalized S-parameters within the documented lumped/wire limits
add_probe(...)record a point observablefeeds Result.find_resonances()
add_ntff_box(...)accumulate far-field datause only when the radiation workflow is benchmarked
preflight(strict=False)validate setup before a long runreturns a coded PreflightReport; use .errors, .warnings, .by_code(...), or .raise_for_failure() for automation gates
mesh_intelligence_report(...)summarize configured grid, preflight issues, and AD memory estimatesuseful for non-uniform and memory-constrained planning
plan_mesh(...)return a serializable MeshPlan for this configured simulationwraps mesh_intelligence_report(), preflight(), and optional S-parameter preflight checks
run(...)advance the simulationreturns a Result object
forward(...)run the differentiable minimal-observable pathuse for jax.grad / outer-jax.jit objectives; returns a ForwardResult, not the full Result

Source, port, and probe builders are documented in detail in Sources & Ports; the fields they populate are described in Results & Observables.

from rfx import GaussianPulse
# Add the sources and observables required by this run.
sim.add_source(
(0.04, 0.03, 0.0125),
"ez",
waveform=GaussianPulse(f0=2e9, bandwidth=0.5),
)
sim.add_probe((0.05, 0.03, 0.0125), "ez")
# until_decay is implemented on the uniform CPML/UPML runner and on the
# non-uniform (dx/dy/dz-profile) runner with CPML/UPML boundaries.
result = sim.run(until_decay=1e-3)

run() returns a tuple-like Result (a NamedTuple) with fields such as time_series, s_params, freqs, ntff_data, and grid — see Results & Observables for the primary field list. Non-finite output is a setup or numerical failure, not successful RF evidence. The automatic run() warning, and the corresponding warning on the uniform single-device forward() path, inspect only time_series and lumped/wire s_params. Non-uniform and distributed forward() paths return before that guard. Inspect every unguarded state, NTFF, DFT-plane, and flux array explicitly with np.isfinite(...) before using it.

After adding a lumped or wire port, compute_s_params=True populates Result.s_params only for that port family. It is not a universal port dispatcher. Microstrip-line, waveguide, and coaxial-line ports use dedicated calculators (compute_msl_s_matrix(), compute_waveguide_s_matrix(), compute_coaxial_line_reflection()). See Sources & Ports for the calculator that matches each port family.

Unless skip_preflight=True, run() checks the configured geometry, sources, ports, mesh, absorber, and selected calculation before allocating the full run. During normal Python execution outside JAX tracing, it may also report measured output problems without changing the returned arrays. Each warning is conditional on the recorded data described below; the absence of a warning is not a convergence or validation result.

The no-field and ring-down witnesses run only on the uniform runner and the single-device non-uniform runner. The ring-down witness further requires a recorded probe series and a GaussianPulse registered through add_source(), add_polarized_source(), lumped/wire add_port(), or add_msl_port(); it does not inspect waveguide, TFSF, or Floquet excitations. Other lanes and source families must be checked explicitly.

SignalInterpretationAction
no field energy was recordedthe recorded probe series, or all returned final-state fields when no series exists, is exactly zerocheck source position, component, amplitude, boundary placement, and probe coverage
ring-down truncatedthe final 5% of a recorded probe series is above -40 dB of its peak for an absorbing-boundary Gaussian-pulse run that used automatic num_periodsthe probe suggests incomplete settling; increase num_periods, or use until_decay where supported, and verify the actual observable separately
non-finite time_series or lumped/wire s_paramsthe solver or setup produced NaN/Inf in an automatically inspected fieldtreat the run as failed; fix setup or stability, and check other result fields explicitly
passivity or per-frequency |S| advisoryan automatically guarded S-parameter path exceeds its documented toleranceinspect mesh, settling, reference plane, normalization, and port-family guidance; do not interpret the affected bin as device physics

Automatic passivity coverage is calculator-specific. Lumped/wire run() and uniform single-device forward() warn on a non-finite entry or an individual |S| > 1.1; they do not test total outgoing column power. MSL and waveguide full-matrix calculators use column-power and per-entry checks with normalization-specific tolerances. compute_coaxial_line_reflection() has no automatic shared passivity warning: inspect its status, residual fields, s11 finiteness, and magnitude directly. No warning means only that an implemented check did not fire; it is not a passivity or convergence certificate.

On the uniform CPML/UPML runner, until_decay=1e-3 monitors the sum of squared field components outside the absorber as an interior field-norm proxy. It stops after that proxy remains below 1e-3 of its peak for the required consecutive checks. This avoids a false stop at a null of a single-cell monitor, but it does not directly prove convergence of every DFT, S-parameter, Harminv, or NTFF observable. The non-uniform (dx_profile / dy_profile / dz_profile) runner supports the same stop on CPML/UPML boundaries, weighting each cell’s squared fields by that cell’s dx*dy*dz volume so graded cells contribute in proportion to their size. On that lane every step-sized buffer is allocated at decay_max_steps and flux monitors must keep the default rectangular DFT window; a non-uniform run with closed boundaries warns and executes the fixed n_steps instead (that lane has no single-cell monitor stop). Other runners may warn or reject until_decay; consult the emitted message instead of assuming it was applied. Closed PEC domains do not normally lose their field norm, so use a fixed run length unless the model contains a real loss mechanism. Explicit n_steps remains appropriate when an exact accumulation window is required.

Use sim.forward(...) when a scalar objective must be differentiated with jax.grad, jax.value_and_grad, or an outer jax.jit-compiled loss function. It returns the minimal ForwardResult needed by differentiable objectives (time series, optional S11 vectors, optional NTFF data) rather than the broader stateful Result from run(...).

Common differentiable inputs are:

InputScope
eps_override=... / sigma_override=...continuous material arrays with grid.shape
port_s11_freqs=...lumped/wire per-port differentiable S11 vectors on the uniform single-device path
rlc_values_override={index: {"R": R, "L": L, "C": C}}scalar values for registered add_lumped_rlc(...) elements on the uniform single-device path
checkpoint_segments=... / checkpoint_every=...reverse-mode memory reduction where the selected runner documents support

Keep setup choices that change array shapes, registered geometry, or the selected runner outside the jitted objective. Unsupported combinations raise instead of silently falling back.

Simulation also exposes a convenience constructor that derives dx, domain, and CPML thickness from the analysis frequency range:

sim = Simulation.auto(freq_range=(1.5e9, 3.5e9), accuracy="standard")

accuracy is one of "draft", "standard", or "high". Because the domain is sized from the frequency range rather than from your structure, auto() emits a warning reminding you to add geometry after construction (or to pass domain / dx overrides). Use the plain constructor when you need to inspect or override the derived setup. See Automation for the underlying auto_configure() helper.

Configured simulations can also produce the same planning artifact:

mesh_plan = sim.plan_mesh(
n_steps=10_000,
available_memory_gb=24.0,
sparameter_calculator="waveguide",
)

MeshPlan is advisory: it records support checks and declaration-only artifact paths, but it does not claim solver replay or physics validation by itself. Passing artifact_root only fills intended paths; it does not write files. Configured-simulation plans use plan_source="configured_simulation", freq_range[0] = None, and accuracy = None in Python (null after JSON serialization) because no auto-configure accuracy preset or lower-band edge is implied by an existing Simulation.

This page covers the documented high-level builder only. Lower-level solver internals, private symbols, and internal extensions are outside the public API until documented. For recommended, limited, and unsupported configurations, see Support Boundaries.