Skip to content

Fix gshank convergence-floor regression, nec2diff comparison bugs (#138), and add issue #139 regression tests - #140

Merged
tmolteno merged 4 commits into
masterfrom
fix/issues-138-139
Nov 9, 2026
Merged

tmolteno merged 4 commits into
masterfrom
fix/issues-138-139

Conversation

@tmolteno

@tmolteno tmolteno commented Nov 9, 2026

Copy link
Copy Markdown
Owner

Three fixes that came out of working through issues #138 and #139:

gshank Shanks-tail convergence floor restored

Issue #131 item 3 raised gshank()'s denm floor 200x (1e-3 → 2e-1 of the largest accelerated term). On decks with wires close to a GN 2 ground (e.g. a radial screen 0.2 m over epsr 13 / sig 0.005 at 2.7 MHz) the degraded Sommerfeld tables make rom2()'s RX = 1e-4 Romberg test unreachable: the integration doubles to the 65536-subdivision cap at every step and never terminates (GB/minute of ROM2 -- STEP SIZE LIMITED output). The floor is restored to 1e-3*den*CRIT_H (keeping CRIT_H = 1.1e-4 scaling); output is byte-identical (modulo timing lines) to the pre-loosening build on sommerfeld2/3 and bruce_sommerfeld, and the regression deck now completes in ~14 ms matching nec2c.

nec2diff fixes (#138)

  • diff() in BaseInput.h used signed comparisons for the near-zero floor, so any two negative values compared equal; sign flips returned inf. Both overloads now normalize by max(|a|,|b|). The four reporter cases give 0.994 / 0.824 / 0.167 / 2.0.
  • main() returns 1 when any section differs, 0 when identical; argc < 3 prints usage and returns 1 instead of aborting on a null std::string.
  • Note: the new metric is ~2x the old near equality, so previously-hidden last-digit engine discrepancies are now visible in nec2diff output.
  • New ctest necpp_nec2diff_issue138 with committed fixtures.

Issue #139 regression tests

  • Unit test [issue139]: wire-order invariance over a Sommerfeld ground (fails on the pre-e3f81e6 inverted c_ggrid::interpolate guard, verified).
  • testharness/data/wire_order_normal.nec / wire_order_reversed.nec decks (cross-validated against nec2c).

Issue #131 item 3 raised gshank()'s convergence floor from
denm = 1e-3*den*CRIT to 2e-1*den*CRIT_H, a 200x loosening. On decks
with wires close to a GN 2 ground (radial screen elevated 0.2 m over
epsr 13 / sig 0.005 at 2.7 MHz) the truncated Shanks tail degrades the
Sommerfeld tables until rom2() can never meet its RX = 1e-4 Romberg
test: the integration doubles to the 65536-subdivision cap at every
step, emits an endless ROM2 -- STEP SIZE LIMITED stream (GB/minute)
and effectively never terminates.

Restore the floor to 1e-3*den*CRIT_H while keeping the milder
CRIT_H = 1.1e-4 tail-test scaling. Output is byte-identical (modulo
timing lines) to the pre-loosening build on sommerfeld2/3 and
bruce_sommerfeld; the regression deck now completes in ~14 ms and
agrees with nec2c (13.906 - j445.84 ohm).

Regression decks: testharness/data/wire_order_normal.nec and
wire_order_reversed.nec (the issue #139 wire-order invariance
geometry, which also failed with the loosened floor).
Add a unit test for github issue #139: a monopole with an explicit
radial screen 0.2 m over a GN 2 Sommerfeld ground, built twice with
the wire cards in natural and reversed order, must give the same
input impedance, accepted power and radiation pattern.

The deck also guards the gshank() convergence floor: with the floor
loosened (issue #131 item 3), rom2() grinds at its subdivision cap
indefinitely and the test fails via the ctest timeout.

Verified against the unfixed c_ggrid::interpolate guard (pre-e3f81e6
inverted branch order): the test fails there, both on the reference
impedance and on order invariance.
Fixes github issue #138.

The real-valued diff() in BaseInput.h tested signed values against
the near-zero floor ((a < 1e-8) && (b < 1e-8)), so any two negative
numbers compared equal: a 178 ohm negative-reactance change or a
-1.71 -> -9.71 dBi gain change reported Difference = 0. A pure sign
flip divided by |a+b| = 0 and printed inf. Both diff() overloads now
normalize by the larger magnitude (|a-b| / max(|a|,|b|)), keeping the
near-zero early-out but keyed on absolute values.

The metric is close to twice the old |a-b|/|a+b| for near-equal
values, so the equalto() thresholds (sum <= 1e-4) now bind about
twice as tightly and previously hidden last-digit engine
discrepancies are visible in nec2diff output.

main() now tracks a flag across the three sections and returns 1 if
any section differs (0 for identical files), so scripts and harnesses
can rely on the exit status. With fewer than two arguments nec2diff
prints usage and returns 1 instead of throwing std::logic_error from
a null std::string construction.

The four reporter cases report 0.994, 0.824, 0.167 (positive control)
and a finite 2.0, matching the issue's suggested-fix values.
Regression fixtures and an exit-code test live in tests/data/issue138/
(ctest necpp_nec2diff_issue138); testharness/data/short_dipole.nec is
the fixture deck.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant