From 48b07dbec08d08938e57b0a99d71371c107a0593 Mon Sep 17 00:00:00 2001 From: Eric Wheeler Date: Sat, 8 Aug 2026 19:52:35 -0700 Subject: [PATCH] fix: assign every etmns_current_source rhs entry, even coincident elements 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 --- src/nec_context.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++--- src/nec_context.h | 2 ++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/nec_context.cpp b/src/nec_context.cpp index 7c9dc66..e6fb98e 100644 --- a/src/nec_context.cpp +++ b/src/nec_context.cpp @@ -3383,6 +3383,43 @@ void nec_context::etmns_circular_wave( nec_float /*cth*/, nec_float /*sth*/, nec } } +/** + * nec_context::etmns_patch_base - locate a patch in the n+2m rhs layout + * @patch_index: zero-based patch index + * + * Return: the first of the patch's two tangential slots. + */ +int nec_context::etmns_patch_base( int patch_index ) const +{ + return m_geometry->n_segments + patch_index*2; +} + +/*-----------------------------------------------------------------------*/ + +/** + * nec_context::etmns_zero_element - zero one element's excitation entries + * @e: right hand side of the matrix equation + * @i: index over the n+m segments and patches + * + * A segment owns e[i]. A patch owns two tangential entries in the n+2m + * layout. + */ +void nec_context::etmns_zero_element( complex_array& e, int i ) +{ + int n = m_geometry->n_segments; + + if ( i < n ) + e[i] = cplx_00(); + else + { + int i1 = etmns_patch_base(i - n); + e[i1] = cplx_00(); + e[i1+1] = cplx_00(); + } +} + +/*-----------------------------------------------------------------------*/ + /*!\brief Incident field of an elementary current source. */ void nec_context::etmns_current_source( nec_float p1, nec_float p2, nec_float p3, nec_float p4, nec_float p5, nec_float p6, complex_array& e ) @@ -3418,8 +3455,13 @@ void nec_context::etmns_current_source( nec_float p1, nec_float p2, nec_float p3 nec_float rs = norm2(pxl,pyl,pzl); if ( rs < 1.0e-30) + { + // Zero the coincident element because the source supplies no field while + // the solver reads every right-hand-side row. + etmns_zero_element(e, i); continue; - + } + nec_float r = sqrt(rs); pxl = pxl/r; pyl = pyl/r; @@ -3462,8 +3504,8 @@ void nec_context::etmns_current_source( nec_float p1, nec_float p2, nec_float p3 else // patches { int patch_index = i - n; - int i1 = n + patch_index*2; // two e-vector slots per patch, based at n - int i2 = i1+1; + int i1 = etmns_patch_base(patch_index); + int i2 = i1 + 1; pxl = wy*qz - wz*qy; // cross product here... pyl = wz*qx - wx*qz; diff --git a/src/nec_context.h b/src/nec_context.h index a4a8c75..2bb3663 100644 --- a/src/nec_context.h +++ b/src/nec_context.h @@ -1016,6 +1016,8 @@ class nec_context nec_float p6, nec_float incident_amplitude, enum excitation_type excite_type, complex_array& e); void etmns_current_source(nec_float p1, nec_float p2, nec_float p3, nec_float p4, nec_float p5, nec_float p6, complex_array& e); + int etmns_patch_base(int patch_index) const; + void etmns_zero_element(complex_array& e, int i); void fblock( int nrow, int ncol, int64_t imax, int ipsym );