Skip to content

excitation: assign every current-source rhs entry at coincident elements - #128

Merged
tmolteno merged 1 commit into
tmolteno:masterfrom
KJ7LNW:fix-etmns-undefined-rhs
Aug 10, 2026
Merged

excitation: assign every current-source rhs entry at coincident elements#128
tmolteno merged 1 commit into
tmolteno:masterfrom
KJ7LNW:fix-etmns-undefined-rhs

Conversation

@KJ7LNW

@KJ7LNW KJ7LNW commented Aug 9, 2026

Copy link
Copy Markdown

Description

An EX type-4 elementary current source placed exactly on the center of a segment or the centroid of a patch made nec2++ print garbage for that element and for the currents coupled to it.

etmns_current_source walks the n+m elements, measures the squared distance from the source point to each element center, and continues when that distance vanishes, src/nec_context.cpp:3419. The entries owned by the skipped element, e[i] for a segment or the two tangential slots for a patch, are never assigned, so the solver factors whatever the array held. The three sibling builders, etmns_voltage_source, etmns_linear_wave, and etmns_circular_wave, assign every row they own unconditionally.

current_vector is a member of the persisting nec_context, src/nec_context.h:849, sized at src/nec_context.cpp:140. safe_array::resize, src/safe_array.h:96-107, grows storage 1.5x and copies only head(_len), and the same vector carries solve results that c_geometry::cabc expands in place. The skipped slot therefore reads residue. Zero is the value the geometry calls for: an element centered on the source point receives no field from it.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Implementation Details

  • nec_context::etmns_patch_base returns a patch's first tangential slot in the n+2m layout, replacing the inline n + patch_index*2 arithmetic in the builder.
  • nec_context::etmns_zero_element assigns zero to one element's entries, one for a segment and two for a patch, off that same base, so the zeroing and the writing agree by construction on where a patch lives.
  • The coincidence guard calls it before continue, so every index in [0, n_plus_2m) is assigned on return.

Reproduction

Three patches tile a plate in the xy-plane at x = +0.1, 0, -0.1, the source sits on the middle patch centroid at the origin, and a wire off to the side gives n > 0 segments so the patch slots are based at a nonzero n.

CM Elementary current source (EX type 4) coincident with a patch centroid.
CE
GW     1     3  5.00000E-01 -5.00000E-02  0.00000E+00  5.00000E-01  5.00000E-02  0.00000E+00  1.00000E-03
SP     0     0  1.00000E-01  0.00000E+00  0.00000E+00  9.00000E+01  0.00000E+00  1.00000E-02
SP     0     0  0.00000E+00  0.00000E+00  0.00000E+00  9.00000E+01  0.00000E+00  1.00000E-02
SP     0     0 -1.00000E-01  0.00000E+00  0.00000E+00  9.00000E+01  0.00000E+00  1.00000E-02
GE     0     0
FR     0     1     0     0  3.00000E+02  0.00000E+00  0.00000E+00  0.00000E+00  0.00000E+00  0.00000E+00
EX     4     0     0     0  0.00000E+00  0.00000E+00  0.00000E+00  9.00000E+01  0.00000E+00  1.00000E+00
RP     0    19    37  1000  0.00000E+00  0.00000E+00  1.00000E+01  1.00000E+01  0.00000E+00  0.00000E+00
EN     0     0     0     0  0.00000E+00  0.00000E+00  0.00000E+00  0.00000E+00  0.00000E+00  0.00000E+00

Before: patch 2 printed 9.88E-324 as its Y-real component, the double whose bit pattern is the integer 2, in a problem whose quantities span 1e-10 to 1e+1. The wire currents were asymmetric about the source plane.

After: patch 2 reads zero in every component and the wire currents are antisymmetric about that plane, segments 1 and 3 printing ±6.9547E-05 ∓1.5977E-05 with the center segment nulling at 2.2E-11, the symmetry a z-directed source imposes.

  PCH   --- PATCH CENTER ---     TANGENT VECTOR 1     TANGENT VECTOR 2    ------- X ------    ------- Y ------
    1   0.100   0.000   0.000  1.8800E+01   176.13  0.0000E+00     0.00 -1.88E+01  1.27E+00  0.00E+00  0.00E+00
    2   0.000   0.000   0.000  0.0000E+00     0.00  0.0000E+00     0.00 -0.00E+00 -0.00E+00  0.00E+00  0.00E+00
    3  -0.100   0.000   0.000  1.8800E+01    -3.87  0.0000E+00     0.00  1.88E+01 -1.27E+00  0.00E+00  0.00E+00

Cross-engine: before this change nec2++ disagreed with nec2c, xnec2c, and the NEC-2 Fortran on currents:current, rdpat:gtot, rdpat:sens, rdpat:tilt, and rdpat:axrt for this deck; after it, those agree.

Those three carry the same skip, at nec2c.c:4579, xnec2c/src/matrix.c:1066, and nec2dxs.f:4347 where the guard branches to the loop-terminating 24 CONTINUE. Their zero at that slot arrives implicitly, from static storage or a first-touch malloc, rather than from an explicit assignment; each reuses one right-hand-side buffer across frequency steps, so the skipped slot carries the previous step's solved current on a multi-frequency deck. Matching corrections are going to those engines as well, so every lineage assigns the entry explicitly.

Three rdpat:gtot rows remain at phi=120, theta=110, where the others print -18.53 dB and nec2++ prints -18.52 dB while the underlying E(theta) and E(phi) agree to five figures: one two-decimal print step. The companion deck that offsets the source and never reaches the guard carries the identical three rows.

The segment branch of the same guard, a type-4 source on a segment center, is covered by the same change.

Testing

  • Tests pass locally

…ments

etmns_current_source skipped an element when the applied-current source sat
exactly on that element's center, leaving its right-hand-side entries at
whatever complex_array left uninitialized. The solver factored that
undefined row, and the reader printed subnormal or otherwise garbage
components for the coincident patch or segment, disagreeing with every
other engine on currents and radiation-pattern quantities that had
previously matched.

- add etmns_patch_base to compute a patch's two tangential slots in the
  n+2m layout, replacing the inline arithmetic duplicated across the
  builder
- add etmns_zero_element to assign zero to one element's entries, segment
  or patch, using that shared base arithmetic
- call etmns_zero_element before the coincident-source skip in
  etmns_current_source so every index in [0, n_plus_2m) is assigned,
  matching the invariant the sibling etmns_* builders already satisfy

Signed-off-by: Eric Wheeler <necpp@z.ewheeler.org>
@tmolteno
tmolteno merged commit 48b07db into tmolteno:master Aug 10, 2026
4 checks passed
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.

2 participants