These helpers propose a mesh, domain, absorber and run length from your geometry and frequency range, and build graded cell profiles. Use them for a first setup, then read what they chose and check it with preflight. For when to grade a mesh at all, see Non-Uniform Mesh.
Planning from geometry
| Helper | Signature | Returns |
|---|---|---|
plan_mesh | plan_mesh(geometry, freq_range, materials=None, accuracy="standard", *, boundary="cpml", dx_override=None, margin_override=None, n_steps_override=None, max_memory_mb=None, artifact_root=None) | MeshPlan |
auto_configure | auto_configure(geometry, freq_range, materials=None, accuracy="standard", *, boundary="cpml", dx_override=None, margin_override=None, n_steps_override=None, max_memory_mb=None, waveform=None, thin_conductors=()) | SimConfig |
geometry: a list of(shape, material_name)pairs.freq_range:(f_min, f_max)in Hz.f_maxsets the cell size,f_minthe margin around the geometry.materials:{name: {"eps_r": ..., "sigma": ...}}for every material ingeometry. Pass it even for library names such as"fr4": a material the planner cannot find is treated as vacuum, and the cell comes out too coarse.accuracy:"draft"(10 cells per wavelength),"standard"(20) or"high"(40). The thinnest feature can force a finer cell than that.max_memory_mb: coarsendxuntil the estimated memory fits.thin_conductors: declared sheets. Each sheet’s plane becomes a z mesh line, so the sheet lands where you drew it.- A thin z feature makes the plan grade z and return a
dz_profile.
plan_mesh wraps auto_configure and adds a serializable record of what it
chose. Prefer it.
import numpy as npfrom rfx import Box, Simulation, plan_mesh
geometry = [(Box((0.0, 0.0, 0.0), (0.02, 0.01, 0.0016)), "fr4")]materials = {"fr4": {"eps_r": 4.4, "sigma": 0.025}}plan = plan_mesh(geometry, freq_range=(1.5e9, 3.5e9), materials=materials, accuracy="standard")print(plan.to_markdown())
kwargs = plan.to_sim_kwargs() # freq_max, domain, boundary, cpml_layers, dx (+ dz_profile)sim = Simulation(**kwargs)print(sorted(kwargs))MeshPlan holds the derived domain, cell_sizes, cfl, absorber,
memory, grid_shape, support_checks and warnings. Export it with
to_dict(), to_json() or to_markdown(). Values rfx could not determine are
None, not missing. artifact_root only records intended output paths; it
writes nothing.
to_sim_kwargs() gives the constructor arguments only. It does not add your
geometry or move it into the new domain. Add the shapes yourself, a few cells
in from the domain edges (where the absorber begins) and with thin layers aligned to the final profile’s cell
edges, then run sim.preflight() and resolve what it reports.
SimConfig.summary() prints the same choices as text.
sim.plan_mesh(...) is the equivalent for a simulation you have already built.
It also runs preflight and can check an S-parameter calculator; see
Simulation.
Simulation.auto(freq_range, ...) builds a simulation from the frequency
range alone, with no geometry; see
Simulation.
Building graded profiles by hand
| Helper | Signature | What it does |
|---|---|---|
make_band_profile | make_band_profile(edges, cell_sizes, *, max_ratio=1.4, protected=None, boundary_cell=None, min_cells=1) | Builds a profile from a declared stack. Every interface in edges lands exactly on a node plane, and every adjacent ratio stays at or below max_ratio. |
smooth_grading | smooth_grading(cells, max_ratio=1.3, *, preserve_regions=None) | Inserts transition cells so no adjacent ratio exceeds max_ratio. |
apply_thirds_rule | apply_thirds_rule(cells, boundary_indices) | Splits the cells at the given material interfaces into 1/3 + 2/3 pairs. |
from rfx import apply_thirds_rule, make_band_profile, smooth_grading
# 10 mm of 1 mm air, a 1.5 mm substrate at 0.25 mm, 13.5 mm of 1 mm air.dz = make_band_profile([0.0, 0.010, 0.0115, 0.025], [1e-3, 0.25e-3, 1e-3], max_ratio=1.4, protected=[False, True, False])print(len(dz), f"{dz.sum() * 1e3:.3f} mm", f"max ratio {np.max(dz[1:] / dz[:-1]):.2f}")
graded = smooth_grading([1e-3] * 4 + [0.25e-3] * 6 + [1e-3] * 4, max_ratio=1.3)print(len(graded), f"{graded.sum() * 1e3:.3f} mm") # longer: cells were insertedmake_band_profile is the one to use when layer faces must sit on grid
planes: the total length and every interface are exact. smooth_grading
adds cells, so the total length and the positions after the inserted
cells change. Recompute your layer coordinates from the final profile’s
cumulative sum. Use max_ratio=1.4 along z and 1.3 in-plane; those are the
ratios rfx has evidence for, and preflight flags larger ones.
Limits
- The plan is a starting point, not a validation. It has not run
Simulation.preflight()for geometry you add later, nor a convergence study. - The cell count per wavelength in
accuracyis a free-space figure. Check that dielectrics still get enough cells: preflight warns below 15 per wavelength in the material. - On a graded mesh, a
Boxwhose faces fall between grid planes snaps to the nearest one. Preflight reports this asgraded_box_rasterization. Align layers to the profile’s cell edges. - Keep the grading out of the absorber: the first and last
cpml_layerscells of a profile on a CPML axis should be uniform. Preflight warns withnu_grading_reaches_absorber.
