circuitRF Reference Guide

3D EM

What circuitRF's 3D solvers are for, how to get them, how to set one up and read the answer, and a worked example you can open.

circuitRF can hand a layout to a 3D solver: Palace or EMerge, two finite-element (FEM) solvers, or openEMS, a finite-difference time-domain (FDTD) solver. It builds the 3D model itself, from the layout, its technology and its bond wires. It meshes the model with Gmsh, runs the solver, and reads the answer back as an ordinary result. The same .cem setup document drives it. You choose a 3D solver in that setup's Solver group, and nothing else about the workflow changes.

This page is the guide. The setup panel's 3D controls, and every .cem field they write, are described control by control in EM Setup ▸ Solver — planar or 3D. This page links into that one rather than repeating it.

When to use 3D, and when not

The planar solvers stay the default wherever they fit. circuitRF's planar method-of-moments solver (see the MoM engine) and the bond-wire kernel in wBond put their unknowns on the metal only. A 3D solver meshes the volume, including the air around the structure. A 3D run therefore costs minutes and gigabytes where a planar run costs seconds. A 3D solver is also a separate program you install. Use 3D for what the planar solvers cannot represent, and as an independent check on them. Do not use it as a replacement.

Structure Use
Planar metal on a layered board or die, and vias that stitch to ground The planar solver. A 3D run is an independent cross-check only
A signal via through a reference plane: a line on each side of the same plane 3D. The planar solver refuses it: its return plane must lie beneath every conductor it solves
Bond-wire arrays over one flat ground wBond's equations or its kernel. A 3D run is the independent reference they are validated against
Bond wires over a stepped or split ground, in a cavity, or under a lid 3D. wBond's ground is one flat plane — see wBond ▸ Equations, the MoM kernel, or FEM and FDTD
Leadframes, lids, cavities, stepped metal, connectors, package-to-board transitions 3D. Nothing planar represents them
A package's capacitance and inductance matrices 3D (Palace). Electrostatic and magnetostatic solves
Resonances of a cavity or a lid: "is there a mode inside my band?" 3D (Palace or EMerge). An eigenmode solve finds them directly
A radiator that is not planar 3D. See Antennas ▸ From a 3D solver

Which 3D solver. FEM (Palace, EMerge) and FDTD (openEMS) suit different geometry. The setup panel says which fits your model when you choose one. This is advice, not a restriction. The full comparison of FEM, FDTD and the planar MoM solver — cost, memory, and which problems suit each — is EM Solvers: MoM, FEM and FDTD.

Running two or more on one setup (Compare…) gives answers from solvers that share no code, and FEM and FDTD share nothing numerically either; their agreement is strong evidence that each has converged. It is a cross-check, not a reference: every solver reads the same generated model, so a mistake in building that model would appear in all of them.

Getting the solvers

circuitRF ships no solver and no mesher. Opening a workspace, editing a 3D setup and looking at its model need none of them. Simulate is the first step that does. On a machine without them it is refused, naming what is missing, and the message offers Install Palace … (or Gmsh, openEMS or EMerge). Settings ▸ 3D EM has the same Install … buttons, and circuitrf solver install palace --yes does the same from a terminal. EM Setup ▸ Letting circuitRF install the 3D solvers is the full description: what is shown before anything downloads, where each program goes, and what happens when an install fails.

What it costs, as measured. Each figure is one machine's measurement, and yours will differ:

Install Measured
Palace, macOS on Apple silicon 52 min, 1.9 GB, on an Apple M4 (10 cores, 16 GB). Built from source
Palace, Linux arm64 29 min, 2.1 GB: three clean installs of Ubuntu 24.04 in a container on an Apple M4 (8 GB, 4 build jobs)
Palace, Windows (in the Linux subsystem) Not yet measured. Reported upstream as most of a day
Gmsh, macOS Under a minute, 0.13 GB
openEMS, macOS 8 min, 0.27 GB, built by openEMS's own script
EMerge, macOS on arm64 About 2 min, 1.0 GB, from ready-built packages, with a Python of its own; from macOS 15 that includes its fast sparse solver (Getting the most speed from EMerge)

Palace is always built from source, because no ready-built Palace exists for macOS or for the Linux subsystem. The build is long but runs in the background, with its progress in the Messages panel, and Cancel stops it at any point.

Palace's licence note

A default Palace build includes ParMETIS, whose licence allows commercial use for evaluation only. If you build Palace, you accept those terms. circuitRF distributes no copy of Palace, so it passes on none.

On Windows, Palace runs inside your own Windows Subsystem for Linux distribution, and circuitRF treats it like a Palace on this computer. Gmsh, openEMS and EMerge run natively. Installing Palace on Windows walks through it step by step, and EM Setup ▸ Palace on Windows has what each missing piece's message says.

By hand. If you prefer to build the solvers yourself, circuitRF finds them on PATH, in a Spack install tree, in a conda environment, or where you name them in Settings ▸ Solvers. An EMerge of your own is never taken from PATH: name its Python, or its virtual environment's folder, in that row or in CIRCUITRF_EMERGE. It runs only the Palace versions it has validated; any Gmsh, openEMS or EMerge runs, with a warning when it is not a version circuitRF has tested. The exact versions and the three build problems met on macOS are in EM Setup ▸ Installing the 3D solvers by hand.

Removing them. Uninstall … in Settings ▸ Solvers, or circuitrf solver remove palace --yes. circuitRF removes only what it installed, and never touches your documents or results. See EM Setup ▸ Removing the 3D solvers.

Setting one up

A 3D setup is an ordinary EM setup whose Solver is not Planar. Create one as any other (New ▸ EM Setup on a layout, see EM Setup), then choose the solver. Every control writes a field of the .cem, so a setup can equally be written as text. The fields below link to their full description.

Leaving something out. In a 3D view, untick an object's, a placed cell's or a port's Model to solve without it while keeping it drawn. A run leaves it out entirely — the air box too is sized without it — and its notes name what was left out. A port that is off is absent, not terminated: no excitation, no sheet, no lumped element, so the gap it spanned is open. The result's ports are the modelled ones renumbered 1…N in their order (P2 off: P1, P3, P4 become 1, 2, 3), and the .sNp header carries one circuitRF-EM 3D port map: line per port, and the .npy a DocumentPort array, so the file says which is which. A reference to something that is off — a modelled port's conductor, a wire's pad, a face boundary — is refused naming both, never dropped; every port off is refused (there is nothing to excite).

Look before you solve. Show 3D on the setup's panel opens the 3D view on the model circuitRF built. It works before any solver is installed, and a port that cannot be built does not empty it: the board is drawn without that port, and the reason the setup would not run is shown across the top of the view. circuitrf explain on the .cem prints the same model as text: every solid, its material and its extent, the ports, the air box and its faces, and an estimate of the problem's size. A .c3d that embeds several setups takes --setup <name> to say which one. circuitrf render x.cem --section xz@y=0um -o cut.svg draws a section through it.

Watching it run, and reading the answer

Before anything runs, circuitRF checks whether the run fits in this machine's memory. The first check uses the model's volumes and the refined shell round each conductor and port. A second check, once Gmsh has reported how many tetrahedra it made, uses the real count. On a bond wire or another small curved conductor the second is the one that counts, because the refinement its curvature asks for is nearly the whole mesh. Past 75 % of memory the run carries a warning naming the estimate and what would shrink it. Past 100 %, Simulate asks before going on.

While it runs, the progress row names the solver's own stages, read from its own log: Meshing (Gmsh) with Gmsh's own stage (curves, surfaces, 3D, the second-order elements, and high-order optimisation with the node count it works on), and gmsh.log in the run folder fills as Gmsh runs; Solving: refinement pass k of N with the unknown count; Adaptive sweep, with the model change — how much the frequency model still changes when a new frequency is solved — and the tolerance it is done below; Reading results. The memory the solver is using is beside it. A 3D run cannot stop early and keep a partial result, so the button reads Cancel.

When it finishes, one line states what the run cost: the wall time, the solver's own peak memory, the tetrahedra before and after refinement, the unknowns, and the preset. The same line is recorded in the result's header.

A driven Palace run also states the power each port loses: driving that port with the others matched, 1 − Σᵢ|Sᵢⱼ|², at the sweep's lowest and highest frequency. This is power that comes out of no port: it went into the dielectric and the metal, or out through an absorbing face. A lossless circuit model cannot show it, and |S21| hides it behind mismatch. A port that loses more than three times the median port, and more than 1 %, is named. If the loss is nearly the same at both ends of the band, it is unlikely to be dielectric loss or radiation, which both grow with frequency. Look at what that port's field reaches.

Where the answer lands. A result is named after its solver, so a 3D run never replaces a planar one or the other solver's:

Problem Result
Driven results/<setup>.palace.sNp and <setup>.palace_em.npy, opened in the Data Display like any S-parameters
Electrostatic results/<setup>.palace_es.npy: C (Maxwell), C_mutual (the capacitors you would draw) and C_ground (each terminal to ground). Printed by circuitrf em
Magnetostatic results/<setup>.palace_ms.npy: L and L_mutual. Printed by circuitrf em
Eigenmode results/<setup>.palace_eig.npy: each mode's f, Q, and where its energy is. Printed by circuitrf em and shown on the panel
openEMS results/<setup>.openems.sNp and <setup>.openems_em.npy
EMerge results/<setup>.emerge.sNp and <setup>.emerge_em.npy; an eigenmode run <setup>.emerge_eig.npy
Compare each solver's own result, as above, and results/<setup>.compare_em.npy holding each one's difference from the reference

For a setup embedded in a .c3d, <setup> is the file's stem and the setup's name with a space between: the setup Driven in board.c3d writes results/board Driven.palace.s15p for fifteen ports. -o moves the Touchstone only. run analysis=em lists every file it wrote in its outputs, the Touchstone first, so the path never has to be put together by hand.

results/<setup>.palace/ keeps everything the run made: the Gmsh script, the mesh, the Palace configuration, both programs' logs, and the saved fields. The run can be repeated by hand from it. An unchanged model reuses its mesh. results/<setup>.emerge/ is EMerge's: the model as data (problem.json), the driver script that reads it, EMerge's log, the arrays it wrote and the saved fields, in the layout a Palace run's fields use, so every field plot draws either. A static or eigenmode setup keeps its own folder beside the driven one: results/<setup>.palace_es/, _ms/ or _eig/.

A port with two terminals on Palace (On Palace) also keeps what its terminal S was converted from, per frequency, in the palace group of <setup>.palace_em.npy: modal_S and modal_V (Palace's modal S and the voltage along each terminal's path, port by excitation), modal_Zpv and modal_kn (each mode's impedance and wavenumber), and modal_G and modal_K (the fitted overlap of a face's modes and its Robin correction). A disputed result can be re-derived from them without running Palace again.

Is this solved?

A 3D run takes minutes to hours, so a 3D view (.c3d) says, for each of its setups, whether a run's result still matches the model. You can tell without opening the fields, and the answer is still there after you close and reopen the document or the workspace.

What "solved" means. A result exists, and nothing the run read has changed since. That covers the 3D view itself (unsaved edits included) and every file the run was solved from: placed layouts and their sub-cells, nested 3D views, the technology, and its material libraries. A circuit-driven thermal run also counts the schematic it ran. A run keeps a copy of the model it solved beside its result, and the check compares contents, not an edit count.

What makes a result out of date. An edit to anything that setup's solver reads: geometry, materials, variables, an object's Model switch (Model: kept in the drawing, left out of the solve in Drawing in 3D), and the setup itself. Each setup is judged on its own:

What never counts, for any setup: hiding or showing an object, its transparency, the field plots, choosing the active setup, the display unit and the snap grid. Those are how the model is drawn, not what is solved. Undoing back to the solved model makes the result current again.

The marks. Each method has its own shape: a diamond for FEM (Palace or EMerge), a triangle for openEMS (FDTD) and a circle for a thermal result; the mark's tooltip names the program. Each method shows at most one mark:

A Compare setup counts for each solver it runs. Shape and fill carry the meaning, so the marks read the same without colour. Hover over a mark for its words: the setup, when it was solved and how long it took, or what has changed since.

FEM (Palace) FDTD (openEMS) Thermal Active setup: solved, current FEM FDTD thermal Active setup: solved, out of date FEM FDTD thermal Another setup: solved, current FEM FDTD thermal Active setup: current, partial FEM, partial FDTD, partial thermal, partial Active setup: out of date, partial FEM, partial FDTD, partial thermal, partial Another setup: current, partial FEM, partial FDTD, partial thermal, partial FEM (Palace) FDTD (openEMS) Thermal Active setup: solved, current FEM FDTD thermal Active setup: solved, out of date FEM FDTD thermal Another setup: solved, current FEM FDTD thermal Active setup: current, partial FEM, partial FDTD, partial thermal, partial Active setup: out of date, partial FEM, partial FDTD, partial thermal, partial Another setup: current, partial FEM, partial FDTD, partial thermal, partial
The solved marks. A diamond is a Palace (FEM) result, a triangle an openEMS (FDTD) result, a circle a thermal result. Filled and solid: the active setup's result matches the model. Hollow: the active setup's result is out of date. Faded: another setup's result matches the model. A star after a mark: that result is partial (cancelled, interrupted or not converged).

Where it appears.

The checks run in the background and never delay opening a document or a workspace. A mark appears once its check finishes, a moment after the document is on screen. After an edit, the check waits for half a second of quiet. It runs again when any run finishes and when a file a 3D view is solved from is saved.

Before a re-run. When the setup you run already has a complete, current result, Simulate asks first: Palace result for 'EM1' is current (solved 14:32, took 18 min). Run again? A Both setup names both results. A partial or out-of-date result runs with no question, because there is no complete result to lose.

From the command line. circuitrf explain <view.c3d> has a Solved section: one line per setup and solver with its state, whether it is partial, when it was solved, how long it took and what has changed. --json carries it too. circuitrf find lists each 3D view's setups with their state. circuitrf em never asks before a re-run; it notes on stderr that the result was already current and runs. See The command line.

The 3D view

Show 3D on a setup's panel opens the 3D view beside it, drawn by the graphics card. It shows the model circuitRF built, and after a run it also shows what the solver made. It is the 3D editor's own view with nothing to edit — the same toolbar, tree, keys and menus, without the drawing tools, the setups, Simulate, the unit and the snap step — and its status lines under the view (the setup's refusals and notes, the mesh, the field) are always shown.

What the mesh tells you about trusting the answer. Look at where the small elements are. After refinement they gather where Palace's own error estimate said the answer needed them: along the edges of strips, around a wire, in a port sheet. If the refined region is on the metal you care about, the refinement did its work. If a feature you care about sits among large elements, the answer at that feature is the coarse mesh's, and a Standard run (with refinement) is the one to trust. Palace also saves its error indicator per element, which the view offers as a field: it shows the error directly, where the mesh shows it only by implication. On an openEMS setup, the grid is the whole accuracy story. A wire much thinner than the cells around it has too much inductance, and the run's notes say so.

Pictures of the 3D view

The 3D view draws on the graphics card, so its pictures cannot be made by the documentation's headless generator. The four below are to be exported from the example with Export picture … at 2×, with the legend on. circuitrf render --field draws a .c3d's clip-plane plot headlessly, as a section rather than the view's perspective; none of these examples carries such a plot yet, and each placeholder says what its headless spelling would need.

How far the dielectric reaches

A stackup gives each dielectric a thickness and a material but no outline, so circuitRF decides how far it reaches sideways. The answer depends on the solver, and for the 3D solvers it is part of what gets solved.

Draw a board outline whenever the board is bigger than its copper, for example when a trace's fringing field runs through substrate beside it, for radiation from the board edge, or for coupling across it. How a placed layout comes into a 3D view is in Drawing in 3D ▸ A placed layout's dielectric.

Walking through the example

File ▸ New ▸ Examples ▸ 3D EM copies a workspace with three cells to a folder you choose and opens it. Each cell is something a planar solver cannot do, or can do only as a comparison. Every setup runs in minutes on a 16 GB laptop. Its README.md opens first and carries the same numbers as this section. The numbers also live in expected-numbers.json beside it, which circuitRF's own tests re-run against, so the two cannot drift apart.

Every time and memory figure below was measured once, on an Apple M4 with 10 cores and 16 GB, running macOS 27.0, Palace 0.18.1 on 10 processes, and Gmsh 4.15.2. Times are wall clock for the whole run. Memory is Palace's own peak over all its processes.

Without Palace, start anyway. Open any setup and press Show 3D to see the model. Press Simulate, and the refusal offering Install Palace … is the expected first step.

Bond wire

A 1 mil (25.4 µm) gold wire with a hexagonal section and a wedge foot at each end, between two 100 µm pads on 100 µm of alumina, inside a closed metal box 3 × 2 × 1.1 mm. Its loop is not symmetric: it rises steeply from the left pad to 290 µm above the pads about a third of the way across, then falls in a long slope to the right pad. A port sheet runs from each pad's outer edge down to the ground.

xmin: PEC, 785 µm beyond xmax: PEC, 785 µm beyond zmin: PEC zmax: PEC, 660.8 µm beyond P1 P2 Materials Alumina Air (not filled) Gold Gold Port (its sheet, projected) XZ section at y = 0 µm A solid is drawn where its bottom ≤ y < its top; a sheet within 0.003 nm of its plane. Ports are drawn projected onto the plane. Air box: ymin, ymax: PEC, 785 µm beyond xmin: PEC, 785 µm beyond xmax: PEC, 785 µm beyond zmin: PEC zmax: PEC, 660.8 µm beyond P1 P2 Materials Alumina Air (not filled) Gold Gold Port (its sheet, projected) XZ section at y = 0 µm A solid is drawn where its bottom ≤ y < its top; a sheet within 0.003 nm of its plane. Ports are drawn projected onto the plane. Air box: ymin, ymax: PEC, 785 µm beyond
The bond-wire cell cut along the wire: two gold pads on 100 um of alumina, the 1 mil wire's loop between them, and a port sheet from each pad's outer edge down to the ground. The box around it is the closed metal box the setup states.

Bond wire 3D.cem runs Palace at Standard. (Measured on the wire's earlier, symmetric 150 µm loop; the Palace figures in this section have not been re-run for the loop above. Kernel W's have.) It takes 179 s, with a peak of 3.1 GB, and gives |S21| = −0.765 dB at 10 GHz and a series inductance of 906 pH at 1 GHz. (The inductance is the π-model's series term, −Im(1/Y21)/ω, from the S-parameters.)

Via through a plane

A 400 µm microstrip on top of a four-layer board, a via through a 900 µm clearance in the middle ground plane, and an inverted microstrip underneath leaving the other way. The laminate has εr 3.66 and tanδ 0.004, and the metal is copper. Both lines return through the same plane, one from above and one from below.

xmin: absorbing xmax: absorbing zmin: absorbing zmax: absorbing P1 P2 Materials Laminate Air (not filled) Copper Copper Copper Copper Port (its sheet, projected) XZ section at y = 0 µm A solid is drawn where its bottom ≤ y < its top; a sheet within 0.013 nm of its plane. Ports are drawn projected onto the plane. Air box: ymin, ymax: absorbing xmin: absorbing xmax: absorbing zmin: absorbing zmax: absorbing P1 P2 Materials Laminate Air (not filled) Copper Copper Copper Copper Port (its sheet, projected) XZ section at y = 0 µm A solid is drawn where its bottom ≤ y < its top; a sheet within 0.013 nm of its plane. Ports are drawn projected onto the plane. Air box: ymin, ymax: absorbing
The via cell cut along the lines: a microstrip on top, the via through a clearance in the ground plane, and an inverted microstrip underneath leaving the other way. The plane is the return for both lines, which is what the planar solver cannot state.

First, the planar solver. Via planar.cem is the same structure for the planar solver, and it is refused:

This EM setup names 'Ground Plane' as its return plane, but its top surface is at 270 µm, which is NOT below the lowest analysis level 'Bottom Copper' at 0 µm. A return plane must lie BENEATH the conductor it feeds, or there is no dielectric slab between them to solve on. Name a conductor below 0 µm, or restrict this setup's analysis levels to conductors above 'Ground Plane'.

circuitrf check reports the same sentence as an error on that setup. It is the only error in the workspace, and it is there on purpose.

Then Palace. Via 3D.cem runs at Draft over 0.1–20 GHz, with 1.5 mm of air on every side of the board and absorbing walls. It takes 62 s, with a peak of 4.8 GB, and gives |S21| = −0.228 dB at 10 GHz and −0.430 dB at 20 GHz.

Package

A ceramic package with its lid on. The 8 × 8 mm cavity has a 254 µm alumina base on a metal floor. Two 200 µm gold leads stop 100 µm short of the side walls, and a 1 mil bond wire runs from each lead to a die pad inside. The lid and seal ring are the closed metal box around it: side walls 100 µm beyond the leads, and a lid 700 µm above the wires, 1.13 mm above the floor. The die itself is not in the model.

xmin: PEC xmax: PEC zmin: PEC zmax: PEC P1 P2 Materials Alumina Air (not filled) Gold Gold Port (its sheet, projected) XZ section at y = 0 µm A solid is drawn where its bottom ≤ y < its top; a sheet within 0.008 nm of its plane. Ports are drawn projected onto the plane. Air box: ymin, ymax: PEC, 2.73 mm beyond xmin: PEC xmax: PEC zmin: PEC zmax: PEC P1 P2 Materials Alumina Air (not filled) Gold Gold Port (its sheet, projected) XZ section at y = 0 µm A solid is drawn where its bottom ≤ y < its top; a sheet within 0.008 nm of its plane. Ports are drawn projected onto the plane. Air box: ymin, ymax: PEC, 2.73 mm beyond
The package cell cut along its leads: a lead on each side, a bond wire from each lead to a die pad, the alumina base, and the lid - the top face of the closed box - above them.

What the example does not show. Every setup is Palace's. The via and the bond wire can also be run with FEM & FDTD - Compare, to see how far openEMS lands from Palace on the same model. That is a cross-check, not a reference.