Skip to content

Commit 5d6dd70

Browse files
authored
Fix/issue 64 cctype include (#92)
* Fixes and optimizations from code review - Fix nec_ground::get_radial_wire_length() returning wrong field - Fix dangling pointer in ASSERT macro (nec_debug.h) - Remove using namespace std from nec2cpp.h header - Fix multi-frequency plane wave excitation loop - Optimize safe_array::resize() to use geometric growth - Refactor c_ggrid::interpolate() for thread safety and speed - Fix safe_array BoundsViol ODR issue * Fix #64, #51: Add missing <cctype> include for std::toupper MSVC does not pull in std::toupper from <iostream> transitively. Add explicit #include <cctype> to misc.cpp and c_geometry.cpp where std::toupper / ::toupper are used. Closes #64, #51
1 parent 049c556 commit 5d6dd70

10 files changed

Lines changed: 145 additions & 140 deletions

File tree

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11
## Unreleased
22

3+
* Fix bug in nec_ground::get_radial_wire_length() which returned radial_wire_count instead
4+
of radial_wire_length.
5+
* Fix dangling pointer bug in ASSERT macro (nec_debug.h) — the thrown c_str() pointer
6+
referred to a destroyed temporary std::string. Now throws std::string by value.
7+
Also changed std::stringstream to std::ostringstream in the ASSERT macro.
8+
* Remove `using namespace std;` from nec2cpp.h header file.
9+
* Fix multi-frequency plane wave excitation: excitation_loop() returned
10+
FREQ_PRINT_NORMALIZATION after completing the incidence angle loop, which caused
11+
simulate() to execute `nfrq=1; mhz=1;` — killing the frequency loop after the first
12+
frequency. Now returns FREQ_LOOP_CONTINUE when more frequencies remain, matching
13+
the pattern used for voltage/current excitation.
314
* Fix error in Sommerfeld ground interpolation thanks to Alexander Schewelew
415
* Update checking for blas, so that other blas can be used like openblas.
16+
* Optimize safe_array::resize() to use geometric growth (doubling) instead of
17+
linear (+_resize_chunk), reducing repeated incremental resizes from O(n²) to
18+
O(n log n) total copy cost.
19+
* Refactor c_ggrid::interpolate(): replace static locals with per-instance cache
20+
members (enables thread safety and correct multi-instance behavior); hoist the
21+
switch(grid) out of the inner coefficient-computation loop; factor duplicated
22+
cubic interpolation code into a single lambda used for all 4 functions.
23+
* Fix safe_array 2D bounds-check test failure: BoundsViol was guarded by
24+
#ifdef NEC_ERROR_CHECK, causing an ODR violation when translation units
25+
compiled with different macro settings were linked together. Moved
26+
BoundsViol definition outside the #ifdef so the exception type always exists.
527

628
## Vresion 1.7.4
729
* Fix bug in reading comments longer than 80 characters (issue #47)

src/c_geometry.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "nec_exception.h"
2323

2424
#include <cstring>
25+
#include <cctype>
2526
#include <stdint.h>
2627

2728
c_geometry::c_geometry()

src/c_ggrid.cpp

Lines changed: 90 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,25 @@ nec_float c_ggrid::m_ysa[3] = {0.,0.,.3490658504};
3838
void c_ggrid::interpolate( nec_float x, nec_float y, nec_complex *f1,
3939
nec_complex *f2, nec_complex *f3, nec_complex *f4 )
4040
{
41-
static int ix, iy, ixs = -10, iys = -10, igrs = -10, ixeg=0, iyeg=0;
42-
static int nxm2, nym2, nxms, nyms, nd, ndp;
43-
static nec_float dx = 1., dy = 1., xs = 0., ys = 0., xz, yz;
44-
static nec_complex a[4][4], b[4][4], c[4][4], d[4][4];
45-
static int nda[3] = {11,17,9}, ndpa[3] = {110, 85, 72};
46-
47-
nec_complex p1, p2, p3, p4, fx1, fx2, fx3, fx4;
48-
41+
static const int nda[3] = {11,17,9}, ndpa[3] = {110, 85, 72};
42+
4943
bool recalculate = true;
50-
51-
if( (x >= xs) && (y >= ys) ) {
52-
ix = (int)((x-xs) / dx)+1;
53-
iy = (int)((y-ys) / dy)+1;
44+
45+
if( (x >= m_ip_xs) && (y >= m_ip_ys) ) {
46+
m_ip_ix = (int)((x - m_ip_xs) / m_ip_dx) + 1;
47+
m_ip_iy = (int)((y - m_ip_ys) / m_ip_dy) + 1;
5448
} else {
5549
/* if point lies in same 4 by 4 point region */
5650
/* as previous point, old values are reused. */
57-
if ( ((ix >= ixeg) && (iy >= iyeg)) &&
58-
((std::abs(ix - ixs) < 2) && (std::abs(iy - iys) < 2)) )
51+
if ( ((m_ip_ix >= m_ip_ixeg) && (m_ip_iy >= m_ip_iyeg)) &&
52+
((std::abs(m_ip_ix - m_ip_ixs) < 2) && (std::abs(m_ip_iy - m_ip_iys) < 2)) )
5953
recalculate = false;
6054
}
61-
55+
6256
if (true == recalculate) {
6357
/* determine correct grid and grid region */
6458
int igr;
65-
59+
6660
if( x <= m_xsa[1])
6761
igr=0;
6862
else {
@@ -71,125 +65,96 @@ void c_ggrid::interpolate( nec_float x, nec_float y, nec_complex *f1,
7165
else
7266
igr=1;
7367
}
74-
75-
if( igr != igrs) {
76-
igrs= igr;
77-
dx= m_dxa[igrs];
78-
dy= m_dya[igrs];
79-
xs= m_xsa[igrs];
80-
ys= m_ysa[igrs];
81-
nxm2= m_nxa[igrs]-2;
82-
nym2= m_nya[igrs]-2;
83-
nxms=(( nxm2+1)/3)*3+1;
84-
nyms=(( nym2+1)/3)*3+1;
85-
nd= nda[igrs];
86-
ndp= ndpa[igrs];
87-
ix= (int)(( x- xs)/ dx)+1;
88-
iy= (int)(( y- ys)/ dy)+1;
89-
} /* if( igr != igrs) */
90-
91-
ixs=(( ix-1)/3)*3+2;
92-
if( ixs < 2)
93-
ixs=2;
94-
ixeg = -10000;
95-
96-
if( ixs > nxm2) {
97-
ixs= nxm2;
98-
ixeg= nxms;
68+
69+
if( igr != m_ip_igrs) {
70+
m_ip_igrs = igr;
71+
m_ip_dx = m_dxa[m_ip_igrs];
72+
m_ip_dy = m_dya[m_ip_igrs];
73+
m_ip_xs = m_xsa[m_ip_igrs];
74+
m_ip_ys = m_ysa[m_ip_igrs];
75+
m_ip_nxm2 = m_nxa[m_ip_igrs] - 2;
76+
m_ip_nym2 = m_nya[m_ip_igrs] - 2;
77+
m_ip_nxms = (( m_ip_nxm2 + 1) / 3) * 3 + 1;
78+
m_ip_nyms = (( m_ip_nym2 + 1) / 3) * 3 + 1;
79+
m_ip_nd = nda[m_ip_igrs];
80+
m_ip_ndp = ndpa[m_ip_igrs];
81+
m_ip_ix = (int)(( x - m_ip_xs) / m_ip_dx) + 1;
82+
m_ip_iy = (int)(( y - m_ip_ys) / m_ip_dy) + 1;
83+
} /* if( igr != m_ip_igrs) */
84+
85+
m_ip_ixs = (( m_ip_ix - 1) / 3) * 3 + 2;
86+
if( m_ip_ixs < 2)
87+
m_ip_ixs = 2;
88+
m_ip_ixeg = -10000;
89+
90+
if( m_ip_ixs > m_ip_nxm2) {
91+
m_ip_ixs = m_ip_nxm2;
92+
m_ip_ixeg = m_ip_nxms;
9993
}
100-
101-
iys=(( iy-1)/3)*3+2;
102-
if( iys < 2)
103-
iys=2;
104-
iyeg = -10000;
105-
106-
if( iys > nym2) {
107-
iys= nym2;
108-
iyeg= nyms;
94+
95+
m_ip_iys = (( m_ip_iy - 1) / 3) * 3 + 2;
96+
if( m_ip_iys < 2)
97+
m_ip_iys = 2;
98+
m_ip_iyeg = -10000;
99+
100+
if( m_ip_iys > m_ip_nym2) {
101+
m_ip_iys = m_ip_nym2;
102+
m_ip_iyeg = m_ip_nyms;
109103
}
110-
104+
105+
// Select the correct array once, outside the inner loop.
106+
complex_array& ar = (m_ip_igrs == 0) ? m_ar1 : (m_ip_igrs == 1) ? m_ar2 : m_ar3;
107+
111108
/* compute coefficients of 4 cubic polynomials in x for */
112109
/* the 4 grid values of y for each of the 4 functions */
113-
int iadz= ixs+( iys-3)* nd- ndp;
110+
int iadz = m_ip_ixs + (m_ip_iys - 3) * m_ip_nd - m_ip_ndp;
114111
for (int k = 0; k < 4; k++ ) {
115-
iadz += ndp;
112+
iadz += m_ip_ndp;
116113
int iadd = iadz;
117-
114+
118115
for (int i = 0; i < 4; i++ ) {
119-
iadd += nd;
120-
121-
switch( igrs ) {
122-
case 0:
123-
p1= m_ar1[iadd-2];
124-
p2= m_ar1[iadd-1];
125-
p3= m_ar1[iadd];
126-
p4= m_ar1[iadd+1];
127-
break;
128-
129-
case 1:
130-
p1= m_ar2[iadd-2];
131-
p2= m_ar2[iadd-1];
132-
p3= m_ar2[iadd];
133-
p4= m_ar2[iadd+1];
134-
break;
135-
136-
case 2:
137-
p1= m_ar3[iadd-2];
138-
p2= m_ar3[iadd-1];
139-
p3= m_ar3[iadd];
140-
p4= m_ar3[iadd+1];
141-
} /* switch( igrs ) */
142-
143-
a[i][k]=( p4- p1+3.*( p2- p3))*.1666666667;
144-
b[i][k]=( p1-2.* p2+ p3)*.5;
145-
c[i][k]= p3-(2.* p1+3.* p2+ p4)*.1666666667;
146-
d[i][k]= p2;
147-
116+
iadd += m_ip_nd;
117+
118+
nec_complex p1 = ar[iadd-2];
119+
nec_complex p2 = ar[iadd-1];
120+
nec_complex p3 = ar[iadd];
121+
nec_complex p4 = ar[iadd+1];
122+
123+
m_ip_a[i][k] = ( p4 - p1 + 3.0 * ( p2 - p3)) * 0.1666666667;
124+
m_ip_b[i][k] = ( p1 - 2.0 * p2 + p3) * 0.5;
125+
m_ip_c[i][k] = p3 - (2.0 * p1 + 3.0 * p2 + p4) * 0.1666666667;
126+
m_ip_d[i][k] = p2;
127+
148128
} /* for ( i = 0; i < 4; i++ ) */
149-
129+
150130
} /* for ( k = 0; k < 4; k++ ) */
151-
152-
xz=( ixs-1)* dx+ xs;
153-
yz=( iys-1)* dy+ ys;
154-
155-
} /* if( (abs(ix- ixs) >= 2) || */
156-
157-
/* evaluate polymomials in x and use cubic */
131+
132+
m_ip_xz = ( m_ip_ixs - 1) * m_ip_dx + m_ip_xs;
133+
m_ip_yz = ( m_ip_iys - 1) * m_ip_dy + m_ip_ys;
134+
135+
} /* if (true == recalculate) */
136+
137+
/* evaluate polynomials in x and use cubic */
158138
/* interpolation in y for each of the 4 functions. */
159-
nec_float xx=( x- xz)/ dx;
160-
nec_float yy=( y- yz)/ dy;
161-
fx1=(( a[0][0]* xx+ b[0][0])* xx+ c[0][0])* xx+ d[0][0];
162-
fx2=(( a[1][0]* xx+ b[1][0])* xx+ c[1][0])* xx+ d[1][0];
163-
fx3=(( a[2][0]* xx+ b[2][0])* xx+ c[2][0])* xx+ d[2][0];
164-
fx4=(( a[3][0]* xx+ b[3][0])* xx+ c[3][0])* xx+ d[3][0];
165-
p1= fx4- fx1+3.*( fx2- fx3);
166-
p2=3.*( fx1-2.* fx2+ fx3);
167-
p3=6.* fx3-2.* fx1-3.* fx2- fx4;
168-
*f1=(( p1* yy+ p2)* yy+ p3)* yy*.1666666667+ fx2;
169-
fx1=(( a[0][1]* xx+ b[0][1])* xx+ c[0][1])* xx+ d[0][1];
170-
fx2=(( a[1][1]* xx+ b[1][1])* xx+ c[1][1])* xx+ d[1][1];
171-
fx3=(( a[2][1]* xx+ b[2][1])* xx+ c[2][1])* xx+ d[2][1];
172-
fx4=(( a[3][1]* xx+ b[3][1])* xx+ c[3][1])* xx+ d[3][1];
173-
p1= fx4- fx1+3.*( fx2- fx3);
174-
p2=3.*( fx1-2.* fx2+ fx3);
175-
p3=6.* fx3-2.* fx1-3.* fx2- fx4;
176-
*f2=(( p1* yy+ p2)* yy+ p3)* yy*.1666666667+ fx2;
177-
fx1=(( a[0][2]* xx+ b[0][2])* xx+ c[0][2])* xx+ d[0][2];
178-
fx2=(( a[1][2]* xx+ b[1][2])* xx+ c[1][2])* xx+ d[1][2];
179-
fx3=(( a[2][2]* xx+ b[2][2])* xx+ c[2][2])* xx+ d[2][2];
180-
fx4=(( a[3][2]* xx+ b[3][2])* xx+ c[3][2])* xx+ d[3][2];
181-
p1= fx4- fx1+3.*( fx2- fx3);
182-
p2=3.*( fx1-2.* fx2+ fx3);
183-
p3=6.* fx3-2.* fx1-3.* fx2- fx4;
184-
*f3=(( p1* yy+ p2)* yy+ p3)* yy*.1666666667+ fx2;
185-
fx1=(( a[0][3]* xx+ b[0][3])* xx+ c[0][3])* xx+ d[0][3];
186-
fx2=(( a[1][3]* xx+ b[1][3])* xx+ c[1][3])* xx+ d[1][3];
187-
fx3=(( a[2][3]* xx+ b[2][3])* xx+ c[2][3])* xx+ d[2][3];
188-
fx4=(( a[3][3]* xx+ b[3][3])* xx+ c[3][3])* xx+ d[3][3];
189-
p1= fx4- fx1+3.*( fx2- fx3);
190-
p2=3.*( fx1-2.* fx2+ fx3);
191-
p3=6.* fx3-2.* fx1-3.* fx2- fx4;
192-
*f4=(( p1* yy+ p2)* yy+ p3)* yy*.16666666670+ fx2;
139+
nec_float xx = ( x - m_ip_xz) / m_ip_dx;
140+
nec_float yy = ( y - m_ip_yz) / m_ip_dy;
141+
142+
// Helper lambda to evaluate cubic for one function index k
143+
auto eval_func = [&](int k, nec_complex* fout) {
144+
nec_complex l_fx1 = ((m_ip_a[0][k] * xx + m_ip_b[0][k]) * xx + m_ip_c[0][k]) * xx + m_ip_d[0][k];
145+
nec_complex l_fx2 = ((m_ip_a[1][k] * xx + m_ip_b[1][k]) * xx + m_ip_c[1][k]) * xx + m_ip_d[1][k];
146+
nec_complex l_fx3 = ((m_ip_a[2][k] * xx + m_ip_b[2][k]) * xx + m_ip_c[2][k]) * xx + m_ip_d[2][k];
147+
nec_complex l_fx4 = ((m_ip_a[3][k] * xx + m_ip_b[3][k]) * xx + m_ip_c[3][k]) * xx + m_ip_d[3][k];
148+
nec_complex l_p1 = l_fx4 - l_fx1 + 3.0 * (l_fx2 - l_fx3);
149+
nec_complex l_p2 = 3.0 * (l_fx1 - 2.0 * l_fx2 + l_fx3);
150+
nec_complex l_p3 = 6.0 * l_fx3 - 2.0 * l_fx1 - 3.0 * l_fx2 - l_fx4;
151+
*fout = ((l_p1 * yy + l_p2) * yy + l_p3) * yy * 0.1666666667 + l_fx2;
152+
};
153+
154+
eval_func(0, f1);
155+
eval_func(1, f2);
156+
eval_func(2, f3);
157+
eval_func(3, f4);
193158
}
194159

195160
#include "electromag.h"

src/c_ggrid.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,31 @@ class c_ggrid
4747
m_ar1.resize(11*10*4);
4848
m_ar2.resize(17*5*4);
4949
m_ar3.resize(9*8*4);
50+
51+
// initialize interpolation cache
52+
m_ip_ixs = -10;
53+
m_ip_iys = -10;
54+
m_ip_igrs = -10;
55+
m_ip_ixeg = 0;
56+
m_ip_iyeg = 0;
57+
m_ip_dx = 1.0;
58+
m_ip_dy = 1.0;
59+
m_ip_xs = 0.0;
60+
m_ip_ys = 0.0;
5061
}
5162

5263
void interpolate( nec_float x, nec_float y,
5364
nec_complex *f1, nec_complex *f2,
5465
nec_complex *f3, nec_complex *f4 );
5566

5667
void sommerfeld( nec_float epr, nec_float sig, nec_float wavelength );
68+
69+
private:
70+
// interpolation cache (per-instance, thread-safe)
71+
int m_ip_ix, m_ip_iy, m_ip_ixs, m_ip_iys, m_ip_igrs, m_ip_ixeg, m_ip_iyeg;
72+
int m_ip_nxm2, m_ip_nym2, m_ip_nxms, m_ip_nyms, m_ip_nd, m_ip_ndp;
73+
nec_float m_ip_dx, m_ip_dy, m_ip_xs, m_ip_ys, m_ip_xz, m_ip_yz;
74+
nec_complex m_ip_a[4][4], m_ip_b[4][4], m_ip_c[4][4], m_ip_d[4][4];
5775
};
5876

5977
class c_ground_wave

src/misc.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "misc.h"
66

77
#include <stdio.h>
8+
#include <cctype>
89

910
using namespace std;
1011

src/nec2cpp.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
#include "math_util.h"
66

7-
using namespace std;
8-
97
int main(int argc, char **argv);
108
void fblock(int nrow, int ncol, int imax, int ipsym);
119

src/nec_context.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,8 +1779,11 @@ enum excitation_return nec_context::excitation_loop(enum processing_state in_fre
17791779
xpr2 += xpr5;
17801780
nphic++;
17811781

1782-
if ( nphic > nphi )
1783-
return FREQ_PRINT_NORMALIZATION;
1782+
if ( nphic > nphi ) {
1783+
if ( nfrq != 1)
1784+
return FREQ_LOOP_CONTINUE;
1785+
return FREQ_PRINT_NORMALIZATION;
1786+
}
17841787

17851788
}
17861789
while( true );

src/nec_debug.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@
2828
#define DEBUG_TRACE(__x) {std::cout << __x << std::endl;}
2929
#define ASSERT(__x) \
3030
{ if (false == (__x))\
31-
{ std::stringstream __ss; \
31+
{ std::ostringstream __ss; \
3232
__ss << "assert in file " << __FILE__ << " at line " << __LINE__;\
33-
std::string __s = __ss.str(); \
34-
throw __s.c_str(); \
33+
throw __ss.str(); \
3534
} \
3635
}
3736
#define ASSERT_EQUAL(__x, __y) ASSERT(fabs((__x) - (__y)) < 1e-15)

src/nec_ground.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ class nec_ground
138138

139139
/*! \brief Returns the length of radial wires used in the ground screen approximation - provided this approximation has been used. */
140140
nec_float get_radial_wire_length() const {
141-
return this->radial_wire_count;
141+
return this->radial_wire_length;
142142
}
143143

144144

0 commit comments

Comments
 (0)