3D Finite-Element Electromagnetics Simulator for RF and mmWave
EdgeFEM is an open-source full-wave frequency-domain FEM solver for RF and microwave structures: hollow waveguides, probe-fed patch antennas, and periodic unit cells. It computes S-parameters, electromagnetic fields, and radiation patterns using lowest-order Nédélec (edge) tetrahedral elements. Accuracy is validated against analytical benchmarks over roughly 5–26 GHz (see Validation).
| Feature | Description |
|---|---|
| S-parameters | Wave ports with 2D discrete port modes and assembled surface-mass ABC; lumped ports for antenna feeds |
| Radiation Patterns | 3D far-field via Stratton-Chu integration over a Huygens surface |
| Periodic Structures | Phase-shifted (Bloch) periodic BCs along one lattice axis, for small unit cells |
| Open Boundaries | First-order ABC and a graded absorbing layer (see Limitations) |
| Dispersive Materials | Debye, Lorentz, Drude, and DrudeLorentz models |
| Python SDK | Full scriptable API with NumPy integration |
| Design Classes | RectWaveguideDesign, PatchAntennaDesign, UnitCellDesign |
| Plotting Module | 14 visualization functions |
| Standard Exports | Touchstone (.sNp), VTK, CSV |
From PyPI:
pip install edgefemA prebuilt wheel currently exists for macOS arm64 / Python 3.9 only; on other platforms and Python versions pip builds from the sdist, which needs cmake, Eigen, and a C++20 compiler. Mesh generation requires gmsh (installed automatically as a dependency).
From source (for development):
# macOS
brew install cmake ninja eigen gmsh
# Clone and build
git clone https://github.com/jman4162/EdgeFEM.git
cd EdgeFEM
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DEDGEFEM_PYTHON=ON
cmake --build build -j
# Set Python path
export PYTHONPATH="$PWD/build/python:$PWD/python:$PYTHONPATH"from edgefem.designs import RectWaveguideDesign
import numpy as np
# Create WR-90 waveguide (X-band)
wg = RectWaveguideDesign(a=22.86e-3, b=10.16e-3, length=50e-3)
wg.generate_mesh(density=10)
# Compute S-parameters at 10 GHz
S = wg.sparams_at_freq(10e9)
print(f"|S11| = {abs(S[0,0]):.4f}") # ~0.01 (see validation report)
print(f"|S21| = {abs(S[1,0]):.4f}") # ~0.99 (matched transmission)import numpy as np
from edgefem.designs import PatchAntennaDesign
# 2.4 GHz WiFi patch on FR-4
patch = PatchAntennaDesign(
patch_length=29e-3, patch_width=38e-3,
substrate_height=1.6e-3, substrate_eps_r=4.4
)
patch.set_probe_feed(y_offset=-5e-3)
# Quick analytical estimates (transmission-line / cavity model)
Z_in = patch.input_impedance(2.4e9)
D = patch.directivity(2.4e9)
print(f"Directivity: {10*np.log10(D):.1f} dBi")
# Full-wave FEM (lumped port, requires gmsh)
patch.generate_mesh(density=12)
s11, _ = patch.simulate(2.4e9)
print(f"|S11| at 2.4 GHz: {abs(s11):.3f}")input_impedance() and radiation_pattern() always use the analytical
models (and warn accordingly); simulate() is the full-wave path. A full
sweep example is in examples/run_patch_fullwave.py.
from edgefem.designs import UnitCellDesign
# Periodic unit cell
cell = UnitCellDesign(period_x=5e-3, period_y=5e-3,
substrate_height=0.5e-3, substrate_eps_r=3.5)
cell.add_patch(width=4e-3, length=4e-3)
cell.generate_mesh(density=20)
# Reflection coefficient at normal incidence
R, T = cell.reflection_transmission(10e9, theta=0, phi=0)
Zs = cell.surface_impedance(10e9)Note: the periodic solve currently applies the Bloch phase along the x lattice
axis only (y walls are natural boundaries), so results are most reliable at
normal incidence. The port is the cell's dominant waveguide mode, not a
Floquet harmonic. See Current Limitations. A runnable version of this
workflow is examples/unit_cell_demo.py.
- Installation Guide - Build from source
- Quick Start - First simulation in 5 minutes
- API Reference - Complete function documentation
- Tutorials - Jupyter notebook examples
- Validation Report - Accuracy benchmarks
- Changelog - What changed and when
| Tutorial | Description |
|---|---|
| 01_rectangular_waveguide.ipynb | WR-90 S-parameters |
| 02_patch_antenna.ipynb | 2.4 GHz patch design |
| 03_unit_cell.ipynb | Metasurface characterization |
| 04_phased_array.ipynb | Active impedance vs scan |
Runnable scripts in examples/ (all perform real FEM solves
unless noted):
| Script | Description |
|---|---|
| 01_waveguide_sparams.py | WR-90 S-parameters at a single frequency |
| 02_frequency_sweep.py | Waveguide sweep with Touchstone export |
| run_patch_fullwave.py | Full-wave probe-fed patch S11 sweep |
| unit_cell_demo.py | Periodic unit cell reflection (single-axis Bloch BC) |
| validation_fresnel.py | Analytical Fresnel/Fabry-Pérot reference curves |
| 03_unit_cell_floquet.py | Floquet phase concepts (prints tables, no solve) |
┌─────────────────────────────────────────────────────────────────┐
│ Python SDK (pyedgefem) │
│ ┌─────────────────────┐ ┌────────────────┐ ┌──────────────┐ │
│ │ Design Classes │ │ Plots Module │ │ Core API │ │
│ │ RectWaveguideDesign │ │ plot_pattern │ │ load_gmsh │ │
│ │ PatchAntennaDesign │ │ plot_sparams │ │ assemble │ │
│ │ UnitCellDesign │ │ plot_coupling │ │ solve │ │
│ └─────────────────────┘ └────────────────┘ └──────────────┘ │
└─────────────────────────────┬───────────────────────────────────┘
│ pybind11
┌─────────────────────────────┴───────────────────────────────────┐
│ C++ Core │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Mesh │ │ Maxwell │ │ Ports │ │ Solver │ │ Post │ │
│ │ (Gmsh) │ │ Assembly │ │ (Wave/ │ │(BiCGSTAB)│ │ (NTF, │ │
│ │ │ │(ABC/absr)│ │ Lumped)│ │ │ │ VTK) │ │
│ └──────────┘ └──────────┘ └────────┘ └──────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
Validated against analytical benchmarks (WR-90/WR-42 waveguide dispersion, cavity eigenmodes, lossy-dielectric attenuation). Representative WR-90 results at ~10 elements/wavelength:
| Metric | Typical (WR-90, 7-12 GHz) | Test pass criterion |
|---|---|---|
| |S21| | 0.997-0.9997 | > 0.90 |
| |S11| | 0.003-0.053 | < 0.15 |
| Phase error vs. -βL | 3-13° | < 15° |
| Passivity |S11|² + |S21|² | ≈ 1.0 | ≤ 1.05 |
Numbers are from tests/benchmark_wr90.cpp, run in CI. A measured mesh-convergence study (scripts/run_convergence_study.py) shows all quantities converging with refinement — phase error at ~O(h²), and |S11| down to 5×10⁻⁴ at 18 elements/wavelength — see the Validation Report for the full tables and limitations.
EdgeFEM is the full-wave FEM engine in a multi-package RF modeling ecosystem:
┌───────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────────────┐ ┌─────────────────────────────────┐ │
│ │ Phased-Array- │ │ RF Metasurface Package │ │
│ │ Antenna-Model │ │ (planned) │ │
│ └──────────┬──────────┘ └────────────────┬────────────────┘ │
└─────────────┼──────────────────────────────┼──────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ EdgeFEM │
│ Full-wave 3D FEM providing: S-params, patterns, coupling │
└─────────────────────────────────────────────────────────────────┘
- Phased-Array-Antenna-Model: Uses EdgeFEM element patterns and coupling for array synthesis
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DEDGEFEM_PYTHON=ON # Python bindings| Option | Default | Description |
|---|---|---|
EDGEFEM_BUILD_SCALAR |
ON | Scalar Helmholtz solver |
EDGEFEM_BUILD_VECTOR |
ON | Maxwell vector solver |
EDGEFEM_PYTHON |
OFF | Python bindings (pybind11) |
ctest --test-dir build -j # All tests
ctest --test-dir build -L smoke # Quick smoke tests
ctest --test-dir build -L pml # PML absorption testsimport edgefem.plots as vp
# S-parameters vs frequency
vp.plot_sparams_vs_freq(freqs, S_list, params=['S11', 'S21'])
# Radiation patterns
vp.plot_pattern_3d(pattern, interactive=True)
vp.plot_pattern_3d_cuts(pattern, title="E/H-plane")
# Coupling analysis
vp.plot_coupling_matrix(S, title="4×4 Array")
vp.plot_active_impedance_scan(angles, Z_active)| Format | Function | Use Case |
|---|---|---|
| Touchstone (.sNp) | export_touchstone() |
RF circuit simulators |
| VTK (.vtu) | export_fields_vtk() |
ParaView visualization |
| CSV | export_pattern_csv() |
Custom post-processing |
If you use EdgeFEM in your research, please cite:
@software{hodge2026edgefem,
author = {Hodge, John},
title = {{EdgeFEM}: A 3D Finite-Element Electromagnetics Simulator for RF and mmWave},
year = {2026},
month = feb,
version = {1.0.0},
publisher = {GitHub},
url = {https://github.com/jman4162/EdgeFEM},
license = {MIT}
}EdgeFEM v1.0 targets small-to-medium waveguide, patch antenna, and unit cell problems. Know these limits before relying on results:
| Feature | Status | Notes |
|---|---|---|
| True tensor (coordinate-stretched) PML | Planned v1.1 | Current absorber applies a scalar average of the stretch tensor: a graded lossy layer, not reflectionless at oblique incidence |
| Wave port formulation | First-order single-mode ABC | Assembled surface-mass operator with 2D discrete port modes (no tuned constants); mesh-convergent S-parameters; higher-order port modes not mode-matched; accuracy degrades near cutoff |
| Floquet ports / harmonic expansion | Planned | Periodic BC applies a Bloch phase along one lattice axis only; the constraint elimination is dense, limiting problem size |
| Inhomogeneous / TEM ports (coax, microstrip) | Not supported | 2D port eigensolver is scalar (hollow homogeneous guides only) |
| Higher-order elements (Tet10) | Planned v1.1 | Lowest-order Whitney elements; use finer mesh |
| Adaptive mesh refinement | Planned v1.1 | Manual mesh refinement in Gmsh |
| Higher-order modes (TE20, TM) | Planned v1.1 | Single-mode analysis only |
| Plane wave excitation (RCS) | Planned v1.2 | — |
| Anisotropic materials | Not planned | Isotropic (complex scalar) only |
| Parallelism (threads/MPI/GPU) | Planned | Single-threaded execution; direct-solver memory limits apply |
| Low-frequency stabilization | Not implemented | Expect conditioning problems well below ~1 GHz |
| Time-domain solver | Not planned | Frequency-domain only |
| Gmsh mesh input | v2 ASCII only | Export with gmsh -format msh2; v4 files are not readable |
For large problems (>1M DOF), adaptive refinement, or reference-plane modal ports, use commercial tools like HFSS or CST.
- Dispersive materials (Debye, Lorentz, Drude, DrudeLorentz models)
- pip-installable Python package (
pip install edgefem) - GitHub Actions CI/CD with automated wheel builds
- Documentation and validation integrity pass, July 2026 — reproducible benchmarks, honest limitations, real mesh QA in CI (see CHANGELOG)
- Assembled port surface-mass ABC with 2D discrete port modes, July 2026 — removes the tuned 0.5 scale factor; S-parameters now mesh-convergent (WR-90 |S11| 0.003-0.053 across band)
- True tensor (coordinate-stretched) PML
- Sparse periodic constraint elimination; dual-axis periodicity
- Higher-order waveguide modes (TE20, TE01, TM modes)
- Higher-order Nédélec elements (Tet10)
- OpenMP parallelization
- Adaptive mesh refinement (h-adaptivity)
- Floquet-harmonic ports for oblique-incidence unit cell analysis
- Plane wave excitation for RCS/scattering
- Surface impedance BC (SIBC)
- Direct solver option (MUMPS)
- MPI distributed solving
- GPU acceleration
- Optimization framework
- GUI application
- Use feature branches; PRs require green CI and updated docs
- clang-tidy, formatting, and unit tests are mandatory
- Large features require an ADR (architecture decision record)
See CONTRIBUTING.md for details.
MIT License. See LICENSE for details.
EdgeFEM builds on excellent open-source projects: