Skip to content

Running momwire as EZNEC's NEC-5 engine

EZNEC Pro+ can drive an external NEC-5 console engine: it writes a deck (EZN5.NEC), launches the engine with two positional arguments, and reads the printout (NEC5.OUT) back for every display it draws. momwire ships that process.

  1. Download momwire-eznec-windows.zip from the latest release.
  2. Unzip it anywhere. Keep the folder together — the exe needs the _internal runtime beside it, and a lone copied-out .exe is the one way a correct download still fails.
  3. Point EZNEC’s external-engine path at momwire-eznec.exe inside that folder.

That is the whole installation. No Python, no environment, nothing on PATH. EZNEC’s interface, models and displays stay EZNEC’s; the electromagnetics become momwire’s.

EZNEC launches its external engine once per frequency point, so the launch cost is the sweep cost. What you point EZNEC at is a small native launcher that keeps a warm momwire engine resident — started on the first calculation, retired after fifteen idle minutes — so every launch after the first costs milliseconds instead of a Python start-up. Measured inside real EZNEC, driven by hand on one machine — a 51-point SWR sweep of a back-yard dipole over real ground, every engine invocation timestamped:

engine51-point SWR sweepper point
momwire launcher, warm3.0 s58 ms
licensed NEC-5 console engine11.0 s215 ms

3.7× on the sweep a user actually runs. Engine-side, the two are at parity — 22 vs 23 ms per launch when invoked the way EZNEC invokes them — and about 35 ms of every point is EZNEC’s own per-point work, the same for either engine. The resident engine wins the sweep because it is bounded where a process-per-point engine is erratic (13–500 ms). For scale, the previous packaging (a frozen one-shot paying the Python import on every launch) took 103 s on the same sweep, engine-side.

The first calculation after a cold start, or after the idle retirement, pays the engine’s start-up once (~5 s on that machine, with no progress shown — EZNEC displays nothing during an external-engine run); if anything about the resident path ever fails, the launcher runs the engine directly instead — the same answer, at one-shot speed, never a broken engine.

The bundle carries three launchers and the one engine they run, and the choice is the engine PATH you set:

momwire-eznec.exe the default — degree-2 B-spline (bs2)
momwire-eznec-razor-2p.exe the tent basis with razor-blade path testing,
at NEC-5's two-point rule
momwire-eznec-razor-nec5.exe the deprecated spelling of razor-2p
momwire-eznec-engine.exe the compute engine the launchers run

Point EZNEC at a launcher, never at momwire-eznec-engine.exe — the engine answers correctly either way, but naming it directly gives up the warm start above for nothing.

They accept the same models — measured, deck by deck, on the whole captured corpus — and answer in different formulations. razor-2p is the tent basis with razor-blade path testing at NEC-5’s two-point rule — the formulation NEC-5 itself uses.

razor-nec5 is the deprecated spelling of the same basis (#785/#794). It runs the same engine and answers identically, and it still ships because an EZNEC engine path is a string typed once and forgotten; dropping the name would break those installs silently. Point new setups at razor-2p.

razor-2p agrees with the licensed engine because it runs the same algorithm, not because it is more correct. It inherits that engine’s discretization error along with its answers, and NEC-5’s razor-blade testing rule is known to walk its impedance slowly — O(1/N).

A note on segment counts, because it is the opposite of the NEC-2 habit. NEC-5’s basis is the tent, so its unknowns and its sources live at knots, not at segment centres. An odd segment count leaves no knot at a dipole’s centre and therefore cannot feed it there — the source lands half a segment off. Use even counts for a centre-fed dipole in this dialect; “odd segments” is a NEC-2 convention, where sources sit at segment centres.

Measured on a 0.476 λ dipole in free space, even meshes, one deck per rung — momwire through this seam, the licensed engine on the same deck text:

segmentslicensed NEC-5bs2razor-2p|razor − NEC-5|
456.118 − 108.593j67.645 − 31.146j56.116 − 108.586j0.007
2066.667 − 35.880j67.739 − 29.155j66.665 − 35.877j0.003
6067.469 − 30.695j67.777 − 28.586j67.467 − 30.693j0.003
16067.670 − 29.281j67.796 − 28.340j67.668 − 29.280j0.003

The twin tracks the reference to 0.003 Ω from 20 segments up and 0.007 Ω at the coarsest rung — flat, not improving, which is what a twin looks like.

That says nothing about which is nearer the truth, so the second measurement asks each basis about itself: the same decks through the same seam, each basis scored against its own N = 160 answer — the finest rung of the table above, so every number here can be read off it.

segmentsbs2 errorrazor-2p error
42.81 Ω80.14 Ω
200.82 Ω6.67 Ω
600.25 Ω1.43 Ω

Both converge. At matched mesh the B-spline basis is 5.8–28× nearer its own limit, which is the O(1/N) walk of razor-blade testing priced in segments.

Neither is “converged at coarse mesh” — bs2 is still 2.8 Ω out at four segments. The difference is how fast the error comes down, not whether it is there.

Where the last ohm actually lives (measured 2026-08-26; parity_limits() in the probe script is the receipt). Extrapolate both ladders and the two formulations nearly meet: razor-2p’s limit lands 0.08–0.21 Ω from bs2’s, depending on the extrapolation model. Of the roughly one ohm between the bases at N = 160 (0.95 Ω through this seam, 1.05 Ω on the probe’s direct ladder), almost all is the twin still descending the O(1/N) path it shares with the licensed engine, and only the fraction-of-an-ohm remainder is formulation. The same run settles a tooling question: with the feed pinned at the exact centre, bs2’s limit is the same whether that centre is a knot (even N) or the middle of a span (odd N) — 0.009 Ω apart — so the knot-feed machinery is not what separates the bases. One deck, free space; but on it, the second table sharpens: the default is not merely nearer its own limit, it is nearer the limit the two formulations share.

So: pick the twin when you want what NEC-5 would have said — checking a published NEC-5 number, or matching a NEC-5 workflow. Pick the default when you want momwire’s own best answer. When they disagree at a practical mesh, neither is broken: most of the gap is the twin’s inherited discretization, shrinking as O(1/N), and what remains — a fraction of an ohm on the deck above — is formulation. A disagreement is information about the mesh before it is information about either engine.

Making another. The basis rides on the filename: everything after eznec- selects it, a Windows .exe stripped first. So a copy you make yourself works — copy a launcher (a couple of hundred kilobytes, not the engine), rename the copy to momwire-eznec-<basis>.exe in the same folder, and that basis answers. This is the same rule the SimNEC portal’s momwire-nec2c-<basis> commands use, with one owner behind both. The bundle ships three rather than all eight because that is what the parity work was about; the other five are a copy away:

bspline bspline-d1 hmatrix arrayblock razor-2p razor-nec5
sinusoidal sinusoidal-galerkin

sinusoidal cannot answer this dialect — every deck in it drives a NODE, and under point matching the match points are the segment centres, so a delta at a node point-samples to nothing in every row and there is no excitation left to solve. It says so by name in the printout rather than answering about a different antenna. sinusoidal-galerkin has no such trouble: its test integral collapses the same delta to a well-defined drive, and it serves the corpus alongside the B-spline and razor families. A filename matching no basis does the same: it refuses, names itself and lists what exists, so a typo can never be served as the default. The match is case-insensitive, as Windows filenames are, so Momwire-EZNEC-Razor-Nec5.exe is the twin too.

Every deck takes exactly one of two paths:

  • Serve: the printout comes back in the engine’s own layout — the same tables, the same headings, the same numeric formats, byte-compatible with the captured output of the licensed engine on our fixture corpus — so everything EZNEC parses out of it just works.
  • Refuse by name: a deck asking for something momwire does not serve gets a NEC ERROR line in the printout that names the card, the wire, or the capability — and, where there is one, the remedy. Nothing is served silently wrong; a refusal sentence is the contract that it never will be.

As of 2026-08-26, 77 of the 80 EZNEC captures in our corpus serve; the three refusals are one named sentence, about one observation point.

  • Geometry: GW wires — straight, junctioned, tapered via stepped radii, exactly as EZNEC emits them (EZNEC resolves its own transforms before writing the deck).
  • Grounds: free space (GN -1), perfect ground (GN 1), the Sommerfeld finite ground (GN 0 / GN 2) including ground contact, and EZNEC’s MININEC-type ground (bare GD).
  • Excitation: EX 0 voltage sources and EX 4 current sources, including phased multi-source drives; sources address nodes the way NEC-5 does.
  • Loads and networks: LD 4 impedance loads, insulation (IS), transmission lines and non-radiating networks (TL / NT), including the mixed table layouts.
  • Requests: impedance runs (PQ / XQ), far-field patterns (RP), and near fields (NE / NH) over all four ground cards — free space, perfect ground, the Sommerfeld finite ground, and the MININEC-type GD (whose near field the engine solves in the medium, and so does momwire). The finite-ground tables ride a Sommerfeld point evaluator and sit within a measured 2–6 % of the licensed engine’s captured cells, the same envelope class as the feedpoint impedances.

The refusals are part of the product, and the interesting ones are honest capability statements rather than deck errors:

  • Buried wires now serve — with measured edges. Wires strictly below the interface over the Sommerfeld ground get impedance, currents and charges: detached buried radials and screens, buried fed elements, and elevated feeds over buried counterpoises. Validation below ground stands on exact identities (the lossless-limit collapse onto free space at 4×10⁻¹⁵, the deep-burial limit onto the infinite-medium solve), on ladder-limit agreement at the half-percent class on the radial/counterpoise classes with the buried-coupling differential matching to ~1 mΩ, and on a licensed NEC-5 asked with its documented below-ground card: the two engines agree to 0.2 % in resistance on a wholly buried fed dipole across depths and to a few percent on a bonded-base vertical over buried radials, and both reproduce the shape of Brown, Lewis and Epstein’s 1937 measured radial-count curve. Two honest notes: a deck’s first buried solve builds its below-interface Sommerfeld tables (about a minute or two today — the accelerated fills are momwire#568), and the refusals below are the map of where the capability ends.
  • What a buried deck still refuses, each by name with its measurement: a wire crossing the interface (the crossing physics is #524 phase 2, and the refusal quotes the three banked reference anchors it must meet); a ground-contact wire combined with buried wires (the fill’s boundary term is O(1) on a contact basis — measured 2.5 relative at the lossless-limit identity, against 10⁻⁵ with the feed lifted clear; an elevated feed over a buried counterpoise serves, and momwire#567 is the lift); NE/NH on decks with buried wires (#524 phase 3); RP on decks with buried wires (the far-zone transmitted asymptotics, momwire#570); buried wires over the perfect ground or GD (no lower medium to be in); sources deeper or pairs farther than the tabulated domains (the sentence states the limit and its extension cost). A wire lying in the interface refuses as the degenerate case it is.
  • A near-field point on a wire’s ground contact (an NE/NH grid point sitting exactly where a wire stands on a finite ground) refuses naming the point: the field there is genuinely singular — a residual charge sits exactly at the observer — and neither momwire’s answer nor the engine’s converges under refinement, so printing either would be publishing a sampling artifact. The sentence quotes the measured divergence and says to move the observation point; the same grid one step off the contact serves.
  • Cards outside the emitted dialect — surface patches, geometry generators (arcs, helices, catenaries), incident-wave excitation, load types other than LD 4, magnetic grounds — refuse naming the card. EZNEC never writes these; a hand-written deck that does gets a sentence, not a guess.

The solver behind the portal is whichever of the two bundled engines you pointed EZNEC at, defaulting to momwire’s degree-2 B-spline — the same physics as the SimNEC portal’s default, where the full eight-engine roster and the cross-basis validation workflow are documented. On the models where we hold a licensed NEC-5 reference, the portal’s printouts agree with the engine’s element for element at the sub-percent level, and the in-house razor-blade formulation (razor-2p) rides the licensed engine’s own convergence path at the 0.01 % level — the receipts behind the word “emulates”.

The bundle’s engine is the momwire.eznec module frozen with PyInstaller (the launcher in front of it is a small C program speaking one socket protocol), and CI gates the routes against each other: the same deck through the launcher, the frozen engine, or the module produces byte-identical printouts. So if you already have a Python environment, the module is there:

Terminal window
pip install momwire
python -m momwire.eznec EZN5.NEC NEC5.OUT

The arguments are exactly EZNEC’s own — positional, cwd-relative, no flags. This spelling is for running decks by hand, scripting a corpus, or working on momwire itself. It cannot be selected from EZNEC’s engine dialog, which is a file picker and wants a path to an executable; reaching it from EZNEC means writing a .bat wrapper, and a wrapper between the host and the engine is where host-side misconfiguration turns into broken-pipe symptoms that read as crashes. Use the packaged exe for that job.