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.
Setting it up
Section titled “Setting it up”- Download
momwire-eznec-windows.zipfrom the latest release. - Unzip it anywhere. Keep the folder together — the exe needs the
_internalruntime beside it, and a lone copied-out.exeis the one way a correct download still fails. - Point EZNEC’s external-engine path at
momwire-eznec.exeinside 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.
Launch economics
Section titled “Launch economics”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:
| engine | 51-point SWR sweep | per point |
|---|---|---|
| momwire launcher, warm | 3.0 s | 58 ms |
| licensed NEC-5 console engine | 11.0 s | 215 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.
Choosing the formulation
Section titled “Choosing the formulation”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 rulemomwire-eznec-razor-nec5.exe the deprecated spelling of razor-2pmomwire-eznec-engine.exe the compute engine the launchers runPoint 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.
Reproduction is not accuracy
Section titled “Reproduction is not accuracy”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:
| segments | licensed NEC-5 | bs2 | razor-2p | |razor − NEC-5| |
|---|---|---|---|---|
| 4 | 56.118 − 108.593j | 67.645 − 31.146j | 56.116 − 108.586j | 0.007 |
| 20 | 66.667 − 35.880j | 67.739 − 29.155j | 66.665 − 35.877j | 0.003 |
| 60 | 67.469 − 30.695j | 67.777 − 28.586j | 67.467 − 30.693j | 0.003 |
| 160 | 67.670 − 29.281j | 67.796 − 28.340j | 67.668 − 29.280j | 0.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.
| segments | bs2 error | razor-2p error |
|---|---|---|
| 4 | 2.81 Ω | 80.14 Ω |
| 20 | 0.82 Ω | 6.67 Ω |
| 60 | 0.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-nec5sinusoidal sinusoidal-galerkinsinusoidal 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.
The contract: serve, or refuse by name
Section titled “The contract: serve, or refuse by name”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 ERRORline 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.
What serves
Section titled “What serves”- Geometry:
GWwires — 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 (bareGD). - Excitation:
EX 0voltage sources andEX 4current sources, including phased multi-source drives; sources address nodes the way NEC-5 does. - Loads and networks:
LD 4impedance 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-typeGD(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.
What refuses, and why
Section titled “What refuses, and why”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/NHon decks with buried wires (#524 phase 3);RPon decks with buried wires (the far-zone transmitted asymptotics, momwire#570); buried wires over the perfect ground orGD(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/NHgrid 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.
What answers underneath
Section titled “What answers underneath”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”.
From a source checkout
Section titled “From a source checkout”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:
pip install momwirepython -m momwire.eznec EZN5.NEC NEC5.OUTThe 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.