# Automation

Channel: release; package: 1.8.0; source: 7d1e97331656dd74ad0f5471653ac0c5effdff70

Page: https://remilab.ai/rfx/versions/v1.8.0/api/automation/
Source: https://github.com/bk-squared/rfx/blob/7d1e97331656dd74ad0f5471653ac0c5effdff70/docs/public/api/automation.mdx

Automation helpers derive a first-pass mesh, domain, absorber, and run budget from
geometry plus a frequency range, so you don't hand-derive every simulation
parameter.

## Core helpers

| Helper | Signature | What it does |
|---|---|---|
| `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)` | derives `dx`, `domain`, CPML layers, timestep, `n_steps`, and (for thin z-features) a `dz_profile`; returns a `SimConfig` |
| `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)` | wraps `auto_configure` and returns a serializable `MeshPlan` with the derived mesh, CFL basis, absorber, memory estimate, resolution/support rows, and declaration-only artifact paths |
| `Simulation.auto` | `Simulation.auto(freq_range, *, accuracy="standard", **kwargs)` | classmethod that builds a `Simulation` with mesh/domain/CPML derived from `freq_range` alone (empty geometry). Add geometry afterward; it warns by design to remind you |
| `smooth_grading` | `smooth_grading(cells, max_ratio=1.3, *, preserve_regions=None)` | inserts geometric transition cells so adjacent ratios outside preserved-region interiors do not exceed `max_ratio` (default 1.3); transitions already inside a preserved region remain unchanged |
| `apply_thirds_rule` | `apply_thirds_rule(cells, boundary_indices)` | at eligible interior material-interface indices, splits neighbouring cells into 1/3 + 2/3 pairs; edge/out-of-range indices and splits below 0.1 µm are skipped |

For a nonempty geometry-derived plan, `accuracy` selects `"draft"` (10
cells/λ), `"standard"` (20 cells/λ), or `"high"` (40 cells/λ); any other value
raises. `Simulation.auto(...)` starts from empty geometry and uses λ/10 for its
initial cell size regardless of that setting, although other preset fields can
still differ. `smooth_grading` and `apply_thirds_rule` are the same primitives
`auto_configure` calls internally when it builds a non-uniform `dz_profile`;
reach for them directly only when hand-building a mesh.

```python
from rfx import Box, plan_mesh

geometry = [(Box((0.0, 0.0, 0.0), (0.02, 0.01, 0.002)), "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())   # inspect the derived mesh before committing to a run

# to_sim_kwargs() carries mesh/domain/boundary/dx (+ dz_profile when present).
mesh_kwargs = plan.to_sim_kwargs()
```

This is a planning example, not a runnable simulation. `to_sim_kwargs()` does
not carry geometry or translate its coordinates into the derived absorber-free
interior. When building the `Simulation`, place the final geometry clear of
CPML, align thin z boundaries to the final profile edges, add sources and
observables, and resolve the resulting preflight report.

`plan_mesh(...)` is the inspectable planning layer. It is a facade around
`auto_configure(...)` and does not duplicate the mesh preset math. `artifact_root`
only declares intended output paths; it never creates directories or writes files.

The serialized `MeshPlan` (`schema_version="mesh-plan/v1"`) reports `plan_source`,
the `freq_range`/`accuracy`/`boundary` inputs, and a stable `cell_sizes` block
(`nominal_dx`, per-axis min/max, and `profiles_present`). Fields whose value is
unknown are `None` rather than omitted — for example the lower frequency bound,
`margin`, or the memory estimate. Serialize with `plan.to_dict()`,
`plan.to_json()`, or `plan.to_markdown()`, and recover constructor kwargs with
`plan.to_sim_kwargs()`. Geometry-derived plans use `plan_source="auto_configure"`
and carry the requested `accuracy`, but they have not run `Simulation.preflight()`
— a `MeshPlan` is a planning artifact, not physics validation.

For an already-configured `Simulation`, use `sim.plan_mesh(...)` instead (it
accepts a memory budget, checkpoint spacing, and optional S-parameter checks, and
runs `preflight()`). See the [non-uniform mesh guide](https://remilab.ai/rfx/versions/v1.8.0/guide/nonuniform-mesh/)
for when to choose each and [Simulation](https://remilab.ai/rfx/versions/v1.8.0/api/simulation/) for `Simulation.auto` and
`sim.plan_mesh`.

## When to use automation

- Use it for first-pass setup, not as a replacement for design review.
- Keep the derived mesh and domain visible in public examples.
- Use the result in public reporting only after it matches the support matrix and
  validation evidence for the intended RF workflow.

## Non-uniform z profiles

For a thin substrate, `auto_configure` may return a graded `dz_profile`
automatically (surfaced in `MeshPlan.cell_sizes` via `profiles_present`). To
hand-build one, use `smooth_grading()` to bound adjacent-cell ratios outside
the interiors listed in `preserve_regions`; ratios already inside a preserved
region are left unchanged. That is useful setup evidence, but it does not by
itself make a graded-z workflow a validated reference path.

Grading inserts transition cells, so physical material coordinates must be
checked against the **final** cumulative cell edges. After adding geometry, run
`sim.preflight()` and resolve `graded_box_rasterization` advisories: they flag a
`Box` that occupies far fewer z cells than the nearby fine spacing implies. See
the [Non-Uniform Mesh](https://remilab.ai/rfx/versions/v1.8.0/guide/nonuniform-mesh/) guide for the alignment
workflow.
