Transient Maxwell (FETD)
Overview
Full-wave electromagnetics in the time domain is the second-order wave equation for the electric field
\[\varepsilon\, \ddot E + \nabla\times(\mu^{-1}\nabla\times E) = 0\]
discretised on Nédélec (curl-conforming) edge elements and marched with the implicit Newmark scheme — the finite-element time-domain (FETD) method (Jin 2002; Taflove & Hagness 2005). Perfectly-conducting (PEC) walls impose E·t = 0, which is enforced by fixing the boundary edge degrees of freedom.
using RasmahA PEC cavity mode
The lowest resonance of a unit PEC cube (with ε = μ = 1) is the (1,1,0) mode at angular frequency ω = π√2. Compute it, then march it in time and check it oscillates at that frequency.
m = tetrahedralize_box(1.0, 1.0, 1.0, 4, 4, 4)
nf = NedelecFESpace(m)
fixed = boundary_edges(nf) # PEC wall edge dofs
λ, modes = maxwell_eigenmodes(nf, 1.0, 1.0; fixed_edges = fixed, nev = 1)
ω = sqrt(λ[1])
println("lowest cavity frequency ω = ", round(ω; digits = 4), " (analytic π√2 = ", round(π * sqrt(2); digits = 4), ")")
E0 = modes[1]
mat = Material(youngs_modulus = 1e3, poisson_ratio = 0.3, relative_permittivity = 1.0, relative_permeability = 1.0)
res = solve_transient_maxwell(m, mat, E0, zeros(length(E0)); nsteps = 150, dt = 0.02, fixed_edges = fixed)lowest cavity frequency ω = 4.3545 (analytic π√2 = 4.4429)
(Es = [[0.0, 0.0, 0.1746227147315899, 0.0, 0.162202601436076, 0.15105960713173489, 0.0, 0.0, 0.1622026014360692, 0.0 … 0.0, 0.0, 0.0, 0.17462271473158777, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17396173461395875, 0.0, 0.16158863380453337, 0.1504878178485094, 0.0, 0.0, 0.16158863380452662, 0.0 … 0.0, 0.0, 0.0, 0.17396173461395673, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17198379813145606, 0.0, 0.15975137887793117, 0.14877677866075156, 0.0, 0.0, 0.15975137887792457, 0.0 … 0.0, 0.0, 0.0, 0.1719837981314543, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.16870387901405598, 0.0, 0.15670474537346435, 0.1459394427846032, 0.0, 0.0, 0.15670474537345794, 0.0 … 0.0, 0.0, 0.0, 0.16870387901405468, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.1641468074944962, 0.0, 0.1524717974632282, 0.14199728992966637, 0.0, 0.0, 0.15247179746322204, 0.0 … 0.0, 0.0, 0.0, 0.16414680749449553, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.15834708233399097, 0.0, 0.14708458016968073, 0.13698016368944824, 0.0, 0.0, 0.14708458016967496, 0.0 … 0.0, 0.0, 0.0, 0.15834708233399106, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.15134860965351327, 0.0, 0.14058387677265893, 0.13092604561402976, 0.0, 0.0, 0.1405838767726536, 0.0 … 0.0, 0.0, 0.0, 0.15134860965351418, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.14320437054779284, 0.0, 0.1330189000644694, 0.12388076767531445, 0.0, 0.0, 0.13301890006446454, 0.0 … 0.0, 0.0, 0.0, 0.1432043705477946, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.13397601999831807, 0.0, 0.12444691979036998, 0.11589766530160361, 0.0, 0.0, 0.12444691979036565, 0.0 … 0.0, 0.0, 0.0, 0.1339760199983207, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.12373342012172264, 0.0, 0.1149328290948593, 0.1070371736081587, 0.0, 0.0, 0.11493282909485553, 0.0 … 0.0, 0.0, 0.0, 0.12373342012172607, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] … [0.0, 0.0, 0.16711084989552147, 0.0, 0.15522502111429962, 0.14456137262251037, 0.0, 0.0, 0.1552250211142926, 0.0 … 0.0, 0.0, 0.0, 0.16711084989552263, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17088248470041625, 0.0, 0.15872839682324508, 0.14782407342719966, 0.0, 0.0, 0.15872839682323836, 0.0 … 0.0, 0.0, 0.0, 0.17088248470041795, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.1733604742311324, 0.0, 0.16103013831679186, 0.14996768988375223, 0.0, 0.0, 0.16103013831678545, 0.0 … 0.0, 0.0, 0.0, 0.17336047423113454, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17452605916630648, 0.0, 0.1621128205381196, 0.1509759940019002, 0.0, 0.0, 0.1621128205381135, 0.0 … 0.0, 0.0, 0.0, 0.17452605916630898, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17437041558553681, 0.0, 0.1619682471718393, 0.15084135253672873, 0.0, 0.0, 0.16196824717183347, 0.0 … 0.0, 0.0, 0.0, 0.17437041558553948, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17289472176981024, 0.0, 0.16059751269321212, 0.14956478477523752, 0.0, 0.0, 0.16059751269320652, 0.0 … 0.0, 0.0, 0.0, 0.1728947217698129, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.17011014928146792, 0.0, 0.15801099408255612, 0.14715595481995128, 0.0, 0.0, 0.1580109940825507, 0.0 … 0.0, 0.0, 0.0, 0.17011014928147045, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.16603777839123782, 0.0, 0.1542282722675662, 0.14363309842799526, 0.0, 0.0, 0.15422827226756103, 0.0 … 0.0, 0.0, 0.0, 0.16603777839124004, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.16070843849258337, 0.0, 0.14927798388825889, 0.13902288495949175, 0.0, 0.0, 0.14927798388825403, 0.0 … 0.0, 0.0, 0.0, 0.1607084384925852, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.15416247471149258, 0.0, 0.1431976045067373, 0.13336021548038052, 0.0, 0.0, 0.1431976045067328, 0.0 … 0.0, 0.0, 0.0, 0.154162474711494, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], times = [0.0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18 … 2.82, 2.84, 2.86, 2.88, 2.9, 2.92, 2.94, 2.96, 2.98, 3.0])
Verification — the oscillation frequency
Probe the largest-magnitude edge dof; it must oscillate as cos(ω t):
free = setdiff(1:nf.nedges, fixed)
probe = free[argmax(abs(E0[i]) for i in free)]
for step in (25, 50, 75, 100, 125)
t = step * 0.02
println("t = ", round(t; digits = 2), " E = ", round(res.Es[step + 1][probe]; digits = 4),
" E₀cos(ωt) = ", round(E0[probe] * cos(ω * t); digits = 4))
endt = 0.5 E = -0.3982 E₀cos(ωt) = -0.3989
t = 1.0 E = -0.247 E₀cos(ωt) = -0.2452
t = 1.5 E = 0.6791 E₀cos(ωt) = 0.6784
t = 2.0 E = -0.5257 E₀cos(ωt) = -0.5282
t = 2.5 E = -0.0811 E₀cos(ωt) = -0.0763
Next steps
- Electromagnetic wave eigenmodes — the frequency-domain resonance.
- Time-domain acoustics — the scalar-wave twin.
