Skip to main content

PySimHub

RapidFEM

Electromagnetic FEM solver written in Rust, distributed as a Python package on PyPI. Two backends behind one geometry/material/physics API: a frequency-domain solver (Nédélec first-kind order-2 edge elements, complex-symmetric sparse linear algebra) and a time-domain DGTD solver (discontinuous Galerkin, Krylov/ETD exponential time integration, model-order reduction). The solver is scale-invariant, so sub-micron RFIC passives (with GDS / PDK-stack import) solve as reliably as metre-scale structures. Optional Flask-based local UI with code editor and live viewer.

Install

pip install rapidfem            # solver only
pip install rapidfem[ui]        # solver + local UI

Wheels for Windows, Linux, and macOS are built via CI. The Rust core is compiled ahead of time — no Rust toolchain required on the user's machine. Gmsh (Python wheel gmsh) is pulled in automatically and provides the OpenCASCADE-based geometry + mesher used by rapidfem.Geometry.

Quick start (Python API)

import numpy as np
import rapidfem as rf

# Build geometry; attach materials + physics directly to entities
g = rf.Geometry(maxh=rf.lambda_maxh(f_max=12e9))
air = g.box(22.86e-3, 10.16e-3, 30e-3, position=(-11.43e-3, -5.08e-3, 0),
            material=rf.Air())

rf.RectWaveguidePort(air.faces.min(axis="z"))
rf.RectWaveguidePort(air.faces.max(axis="z"))
rf.PEC(*air.faces.unassigned)

g.mesh()

# Define the problem once, run any number of analyses on it
prob = rf.Problem(g)                      # Problem is the frequency-domain ProblemFD
result = prob.sweep(np.linspace(8e9, 12e9, 21))
print(result.frequencies.shape, result.sparams.shape)

# Same Problem can also drive an eigenmode solve or a far-field pattern:
# modes   = prob.eigenmode(target_frequency=10e9, n_modes=6)
# pattern = prob.farfield(result, freq_idx=10, port_idx=0)

See python_src/rapidfem/examples/ for end-to-end runs: microstrip and coupled lines, iris / stepped-impedance filters, patch / Vivaldi / inverted-F antennas (PML + far-field), pyramidal horns, dielectric resonators, and the fd_rfic_* on-chip passives. RFIC geometry comes from a process stack and layout via rapidfem.rfic (rfic.Stack, Geometry.from_gds).

Importing external CAD and meshes

g.load(path) brings external geometry into the scene; the action is chosen from the file extension:

g = rf.Geometry(maxh=rf.lambda_maxh(f_max=20e9))

# STEP / IGES / BREP land in the same OpenCASCADE kernel as the primitives,
# so the result is a normal GeoObject: boolean it, transform it, select its
# faces, attach materials and physics, all exactly like a g.box(...).
part = g.load("horn.step", material=rf.Air())   # mm STEP -> metres by default
post = g.cylinder(radius=0.5e-3, height=5e-3)
g.cut(part, post)                                # compose CAD with primitives
g.rotate(part, math.pi / 2, axis=(0, 1, 0))      # full transform API applies
rf.RectWaveguidePort(part.faces.max(axis="z"))
rf.PEC(*part.faces.unassigned)
g.mesh()

# Place/orient any import at load time, like a primitive's position= kwarg:
part = g.load("horn.step", position=(0, 0, 5e-3), rotation=(math.pi, (0, 0, 1)))

# STL is a surface triangulation, healed into a meshable solid. It is a
# discrete body (its geometry IS the mesh), so it stays standalone: it takes a
# material, physics, placement and meshing, but it cannot be combined with OCC
# primitives or boolean ops (use a STEP/IGES/BREP export for that). STL is
# unit-less, pass scale= (metres per file unit) for a model authored in mm.
g = rf.Geometry(maxh=0.5e-3)
blob = g.load("antenna.stl", material=rf.Air(), scale=1e-3, position=(0, 0, 1e-3))

# A pre-built .msh volume mesh is already tessellated, so loading one switches
# the geometry into mesh mode: its named physical groups become selectable
# handles you attach materials and physics to. g.mesh() then bakes the
# bindings (no remeshing) and the usual Problem/sweep pipeline runs unchanged.
g = rf.Geometry()
scene = g.load("waveguide.msh")
scene.group("air").material = rf.Air()
rf.RectWaveguidePort(scene.group("port_in"))
rf.RectWaveguidePort(scene.group("port_out"))
rf.PEC(scene.group("walls"))
g.mesh()
result = rf.Problem(g).sweep(np.linspace(8e9, 12e9, 21))

unit= sets the target unit OpenCASCADE converts a STEP/IGES file into (default "M", so a millimetre file comes in at metre coordinates); scale= is an extra metres-per-file-unit factor for unit-less STL or a mis-declared CAD unit. See examples/fd_step_import.py for a full STEP-driven sweep.

Local UI

rapidfem serve ./my_project/

Opens a browser window with a CodeMirror Python editor, a 3D geometry / mesh / field viewer (raw WebGL2), and S-parameter plots. The geometry view updates on save (Ctrl+S); mesh and solver runs are explicit. Results stream in as the solve runs; fields are fetched on demand as you scrub frequency and port. Use rapidfem.show(g) to send a geometry to the viewer.

Features

  • Geometry builder — OpenCASCADE primitives with boolean ops, transforms and fillet/chamfer; ready-made RF structures in rf.structures (coax, microstrip, CPW, stripline, waveguides, helix) build geometry + ports in one call
  • External CAD / mesh importg.load(path) pulls in STEP / IGES / BREP solids as fully composable primitives, heals STL surfaces into meshable solids, or loads a pre-built .msh and exposes its named physical groups for material / physics binding
  • RFIC / GDSrapidfem.rfic process stacks and Geometry.from_gds build on-chip passives, solved scale-invariantly down to sub-micron features
  • Canonical Nédélec R2 elements — first-kind order-2 curl–curl vector element, 20 DOFs per tetrahedron
  • Excitations — rectangular waveguide ports (arbitrary TE modes), lumped ports (TEM, multi-line voltage integral), coax and wave ports, Floquet plane-wave port (normal incidence), first-order absorbing boundary
  • PML — anisotropic stretched-coordinate perfectly matched layer
  • Lossy materials — complex permittivity with loss tangent + conductivity, surface impedance for metals, Debye dispersion; cached across sweeps
  • Sparse solvers — pure-Rust rslab complex-symmetric LDLᵀ (Bunch-Kaufman) baseline with a-priori memory estimates; optional MKL PARDISO (complex-symmetric LDLᵀ) where mkl_rt is installed
  • Frequency sweep — assembles E/B once, refactors only the frequency- dependent K per point, reuses the symbolic LU pattern
  • Eigenmode solver — shift-invert Lanczos on the complex-symmetric system
  • Adaptive refinement — residual error estimator with Dörfler marking, exports a size field for gmsh re-meshing
  • Output — Touchstone (.s1p/.s2p/.snp), VTK field export, far-field NFFT
  • Parallel assembly — rayon-based element matrix evaluation

Time-domain backend (DGTD)

ProblemTD, behind the same API, compiles a structure into an explicit linear ODE dy/dt = A·y and exposes it as a model at every level:

  • DGTD — nodal discontinuous Galerkin on tetrahedra, upwind or energy-conserving central flux
  • Exponential time integration — matrix-free Krylov/ETD propagator, exact for the linear system at any step size (no CFL limit)
  • Model export / reduction — the RHS, the verbatim sparse operator A, an exponential stepper, or Krylov-projected reduced models
  • Materials — heterogeneous, lossy, anisotropic and Debye dispersive media; matched absorbing layers; periodic boundaries
  • Output — field probes, RFT transfer function, VTK field-animation export
import rapidfem as rf

ptd  = rf.ProblemTD.box(size=(1, 1, 1), cells=(2, 2, 2), order=2)
traj = ptd.transient(y0, dt=0.02, steps=200)   # turnkey transient
rom  = ptd.reduce(y0, dim=60)                   # model-order reduction
A    = ptd.state_space()                        # the verbatim operator

Method notes and the ProblemTD API are in docs/td-backend.md.

Solver backends

Solver Type Notes
rslab Complex-symmetric LDLᵀ (Bunch-Kaufman) Pure Rust, no native dependencies — always available. Numeric-only refactorisation across sweeps, a-priori RAM gate
MKL PARDISO Complex-symmetric LDLᵀ Opt-in, needs mkl_rt on PATH

Select with RAPIDFEM_SOLVER ("auto", "pardiso", "rslab"), set before import rapidfem. Default "auto" tries PARDISO → rslab. Optional MKL: conda install mkl / pip install mkl (ensure mkl_rt is on PATH).

Performance

WR-90 iris waveguide driven sweep, 10 GHz, 2-port:

Mesh DOFs PARDISO faer
693 tets 5 512 0.14 s 0.22 s
1 096 tets 8 382 0.06 s 0.45 s
2 595 tets 19 196 0.17 s 1.39 s
3 284 tets 23 968 0.21 s 1.98 s

Larger: 327 k DOFs driven sweep (PARDISO) ~5 s/freq; 905 k DOFs eigenmode (3-turn spiral, shift-invert Lanczos) ~54 s.

Verification

cargo test --release checks element-level functions to machine precision (1e-12 – 1e-16). End-to-end S-parameter accuracy is tracked in tests/validation/ against analytical solutions and reference solvers.

Acknowledgments

rapidfem began life as a Rust port of EMerge (PyPI), Robert Fennis' open-source Python electromagnetic FEM solver. EMerge is the project that inspired this one — its clear, script-first design shaped how rapidfem's geometry / material / physics API feels today, and the early releases ported its Python implementation to Rust. Warm thanks to Robert Fennis for building and sharing it.

The solver kernels have since been independently re-derived from primary sources (Nédélec's edge-element construction, standard microwave theory, and the barycentric integration identities); the derivations, completeness proofs and entrywise cross-checks live in derivations/.

License

GPL-3.0-or-later with the Gmsh additional permission — see LICENSE. Copyright (C) Milan Rother and rapidfem contributors; commercial terms available.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rapidfem-0.18.1.tar.gz (84.2 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rapidfem-0.18.1-cp310-abi3-win_amd64.whl (85.5 MB view details)

Uploaded CPython 3.10+Windows x86-64

rapidfem-0.18.1-cp310-abi3-manylinux_2_39_x86_64.whl (85.6 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.39+ x86-64

rapidfem-0.18.1-cp310-abi3-macosx_11_0_arm64.whl (84.9 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file rapidfem-0.18.1.tar.gz.

File metadata

  • Download URL: rapidfem-0.18.1.tar.gz
  • Upload date:
  • Size: 84.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rapidfem-0.18.1.tar.gz
Algorithm Hash digest
SHA256 e567a851f43aba177f5dd32c8c51dd01210a3de478d87f40bc302f9fbbce213c
MD5 1f2764c085a02a4fd14e7083dd28cc74
BLAKE2b-256 461ee1fd9ba64c1562b380c825dd365b9461b1037d45f130f5520c1db3e17ba4

See more details on using hashes here.

Provenance

The following attestation bundles were made for rapidfem-0.18.1.tar.gz:

Publisher: wheels.yml on milanofthe/rapidfem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rapidfem-0.18.1-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: rapidfem-0.18.1-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 85.5 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rapidfem-0.18.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 1636d2ab27421760e2cd8f4c2e53433477fc95ce3d3eb4b641fe4f2e0ab74ce0
MD5 9af66467318be9fcdd8bbb7363de68c6
BLAKE2b-256 faac042a228fd9724017edd8cd752f6549d8e3d30d707d12c52f3b945670e842

See more details on using hashes here.

Provenance

The following attestation bundles were made for rapidfem-0.18.1-cp310-abi3-win_amd64.whl:

Publisher: wheels.yml on milanofthe/rapidfem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rapidfem-0.18.1-cp310-abi3-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for rapidfem-0.18.1-cp310-abi3-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 f61ddbba58da475a5b24b5b8c03c0bd8f99a76a632ada0edaf6ce813ce8d46da
MD5 f245b4f87d366b0db8635945bd13fa32
BLAKE2b-256 42159be5c20bd01d0999b9c608bbc1f6dc42ba5e386ba177aa58632a6674a82b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rapidfem-0.18.1-cp310-abi3-manylinux_2_39_x86_64.whl:

Publisher: wheels.yml on milanofthe/rapidfem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rapidfem-0.18.1-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rapidfem-0.18.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5e6cdae7ba60b84e07e800f0ecb4daf2bb8ad8c3317fadf7253a25b3a3d9a320
MD5 9101cbe6677ad0256b1c28efe63e4311
BLAKE2b-256 14fefa2275baabb72deb2fd903e398ff059ead9e4ff3cc2bd051a15036d00de1

See more details on using hashes here.

Provenance

The following attestation bundles were made for rapidfem-0.18.1-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: wheels.yml on milanofthe/rapidfem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page