PyNEC 2.2.1__tar.gz → 2.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {pynec-2.2.1 → pynec-2.2.2}/PKG-INFO +1 -1
  2. {pynec-2.2.1 → pynec-2.2.2}/PyNEC.egg-info/PKG-INFO +1 -1
  3. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_geometry.cpp +18 -10
  4. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/matrix_algebra.cpp +5 -5
  5. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/misc.cpp +24 -2
  6. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/misc.h +1 -1
  7. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_context.cpp +6 -6
  8. {pynec-2.2.1 → pynec-2.2.2}/pyproject.toml +1 -1
  9. {pynec-2.2.1 → pynec-2.2.2}/tests/test_input_parameters.py +3 -3
  10. {pynec-2.2.1 → pynec-2.2.2}/tests/test_near_field.py +3 -3
  11. {pynec-2.2.1 → pynec-2.2.2}/tests/test_norm_rx_pattern.py +6 -4
  12. {pynec-2.2.1 → pynec-2.2.2}/tests/test_patches.py +7 -3
  13. {pynec-2.2.1 → pynec-2.2.2}/tests/test_radiation_pattern.py +4 -3
  14. {pynec-2.2.1 → pynec-2.2.2}/tests/test_structure_currents.py +16 -9
  15. {pynec-2.2.1 → pynec-2.2.2}/tests/test_structure_excitation.py +14 -5
  16. {pynec-2.2.1 → pynec-2.2.2}/LICENCE.txt +0 -0
  17. {pynec-2.2.1 → pynec-2.2.2}/MANIFEST.in +0 -0
  18. {pynec-2.2.1 → pynec-2.2.2}/PyNEC.egg-info/SOURCES.txt +0 -0
  19. {pynec-2.2.1 → pynec-2.2.2}/PyNEC.egg-info/dependency_links.txt +0 -0
  20. {pynec-2.2.1 → pynec-2.2.2}/PyNEC.egg-info/requires.txt +0 -0
  21. {pynec-2.2.1 → pynec-2.2.2}/PyNEC.egg-info/top_level.txt +0 -0
  22. {pynec-2.2.1 → pynec-2.2.2}/PyNEC.py +0 -0
  23. {pynec-2.2.1 → pynec-2.2.2}/PyNEC_wrap.cxx +0 -0
  24. {pynec-2.2.1 → pynec-2.2.2}/README.md +0 -0
  25. {pynec-2.2.1 → pynec-2.2.2}/example/antenna_util.py +0 -0
  26. {pynec-2.2.1 → pynec-2.2.2}/example/basic_usage.py +0 -0
  27. {pynec-2.2.1 → pynec-2.2.2}/example/context_clean.py +0 -0
  28. {pynec-2.2.1 → pynec-2.2.2}/example/dipole.py +0 -0
  29. {pynec-2.2.1 → pynec-2.2.2}/example/impedance_plot.py +0 -0
  30. {pynec-2.2.1 → pynec-2.2.2}/example/logperiodic_opt.py +0 -0
  31. {pynec-2.2.1 → pynec-2.2.2}/example/monopole.py +0 -0
  32. {pynec-2.2.1 → pynec-2.2.2}/example/monopole_realistic_ground_plane.py +0 -0
  33. {pynec-2.2.1 → pynec-2.2.2}/example/optimized.py +0 -0
  34. {pynec-2.2.1 → pynec-2.2.2}/example/radiation_pattern.py +0 -0
  35. {pynec-2.2.1 → pynec-2.2.2}/example/test_ai.py +0 -0
  36. {pynec-2.2.1 → pynec-2.2.2}/example/test_charge_densities.py +0 -0
  37. {pynec-2.2.1 → pynec-2.2.2}/example/test_ne_nh.py +0 -0
  38. {pynec-2.2.1 → pynec-2.2.2}/example/test_nrp.py +0 -0
  39. {pynec-2.2.1 → pynec-2.2.2}/example/test_rp.py +0 -0
  40. {pynec-2.2.1 → pynec-2.2.2}/example/test_rp2.py +0 -0
  41. {pynec-2.2.1 → pynec-2.2.2}/example/test_se.py +0 -0
  42. {pynec-2.2.1 → pynec-2.2.2}/example/test_structure_currents.py +0 -0
  43. {pynec-2.2.1 → pynec-2.2.2}/example/test_surface_patch_currents.py +0 -0
  44. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/AntennaInput.h +0 -0
  45. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/BaseInput.h +0 -0
  46. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/CurrentInput.h +0 -0
  47. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/PowerBudget.h +0 -0
  48. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/RadiationInput.h +0 -0
  49. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/XGetopt.cpp +0 -0
  50. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/XGetopt.h +0 -0
  51. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_evlcom.cpp +0 -0
  52. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_evlcom.h +0 -0
  53. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_geometry.h +0 -0
  54. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_ggrid.cpp +0 -0
  55. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_ggrid.h +0 -0
  56. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_plot_card.cpp +0 -0
  57. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/c_plot_card.h +0 -0
  58. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/common.h +0 -0
  59. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/config.h.in +0 -0
  60. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/electromag.cpp +0 -0
  61. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/electromag.h +0 -0
  62. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/libNEC.cpp +0 -0
  63. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/libnecpp.h +0 -0
  64. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/math_util.h +0 -0
  65. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/matrix_algebra.h +0 -0
  66. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec2cpp.h +0 -0
  67. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_card_parser.h +0 -0
  68. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_context.h +0 -0
  69. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_debug.h +0 -0
  70. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_exception.cpp +0 -0
  71. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_exception.h +0 -0
  72. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_ground.cpp +0 -0
  73. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_ground.h +0 -0
  74. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_output.cpp +0 -0
  75. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_output.h +0 -0
  76. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_radiation_pattern.cpp +0 -0
  77. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_radiation_pattern.h +0 -0
  78. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_results.cpp +0 -0
  79. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_results.h +0 -0
  80. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_structure_currents.cpp +0 -0
  81. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_structure_currents.h +0 -0
  82. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/nec_wire.h +0 -0
  83. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/safe_array.h +0 -0
  84. {pynec-2.2.1 → pynec-2.2.2}/necpp_src/src/typesafe_stdint.h +0 -0
  85. {pynec-2.2.1 → pynec-2.2.2}/setup.cfg +0 -0
  86. {pynec-2.2.1 → pynec-2.2.2}/setup.py +0 -0
  87. {pynec-2.2.1 → pynec-2.2.2}/tests/test_charge_densities.py +0 -0
  88. {pynec-2.2.1 → pynec-2.2.2}/tests/test_examples.py +0 -0
  89. {pynec-2.2.1 → pynec-2.2.2}/tests/test_get_gain.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyNEC
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: Python Antenna Simulation Module (nec2++) object-oriented interface
5
5
  Author-email: Tim Molteno <tim@physics.otago.ac.nz>
6
6
  License-Expression: GPL-3.0-only
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyNEC
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: Python Antenna Simulation Module (nec2++) object-oriented interface
5
5
  Author-email: Tim Molteno <tim@physics.otago.ac.nz>
6
6
  License-Expression: GPL-3.0-only
@@ -1971,12 +1971,18 @@ void c_geometry::sc_card(int i2,
1971
1971
  default:
1972
1972
  throw nec_exception("PATCH DATA ERROR ns ", this->patch_type );
1973
1973
  }
1974
- patch( this->patch_type, i2,
1975
- this->patch_x1(0), this->patch_x1(1), this->patch_x1(2),
1974
+ /* The patch shape is conveyed by the ny argument (i2); nx must be 0 so
1975
+ that patch() treats this as a single shaped patch rather than an
1976
+ nx-by-ny grid (nx > 0 would expand each SC card into a grid of
1977
+ patches, bloating the interaction matrix). This mirrors the
1978
+ file-parser path (parse_sc_card), which calls
1979
+ patch(st.card_int_1 = 0, st.card_int_2, ...). */
1980
+ patch( 0, i2,
1981
+ this->patch_x1(0), this->patch_x1(1), this->patch_x1(2),
1976
1982
  this->patch_x2(0), this->patch_x2(1), this->patch_x2(2),
1977
1983
  this->patch_x3(0), this->patch_x3(1), this->patch_x3(2),
1978
1984
  this->patch_x4(0), this->patch_x4(1), this->patch_x4(2));
1979
-
1985
+
1980
1986
  _prev_sc = true;
1981
1987
  }
1982
1988
 
@@ -2024,16 +2030,18 @@ void c_geometry::sc_multiple_card(int i2,
2024
2030
  default:
2025
2031
  throw nec_exception("PATCH DATA ERROR i2 = ", i2 );
2026
2032
  }
2027
-
2028
- patch( this->patch_type, i2,
2029
- this->patch_x1(0), this->patch_x1(1), this->patch_x1(2),
2033
+
2034
+ /* See sc_card(): nx must be 0 to avoid patch() generating an nx-by-ny
2035
+ grid of patches for each linked SC card in the patch string. */
2036
+ patch( 0, i2,
2037
+ this->patch_x1(0), this->patch_x1(1), this->patch_x1(2),
2030
2038
  this->patch_x2(0), this->patch_x2(1), this->patch_x2(2),
2031
2039
  this->patch_x3(0), this->patch_x3(1), this->patch_x3(2),
2032
2040
  this->patch_x4(0), this->patch_x4(1), this->patch_x4(2));
2033
-
2041
+
2034
2042
  m_output->nec_printf( "\n"
2035
2043
  " %5d%c %10.5f %11.5f %11.5f %11.5f %11.5f %11.5f",
2036
- this->patch_type, ipt[i2],
2044
+ this->patch_type, ipt[i2],
2037
2045
  this->patch_x1(0), this->patch_x1(1), this->patch_x1(2),
2038
2046
  this->patch_x2(0), this->patch_x2(1), this->patch_x2(2));
2039
2047
 
@@ -2475,7 +2483,7 @@ void c_geometry::read_geometry_card(FILE* input_fp, char *gm,
2475
2483
  nec_float *in_x2, nec_float *in_y2, nec_float *in_z2,
2476
2484
  nec_float *in_rad )
2477
2485
  {
2478
- char line_buf[134];
2486
+ char line_buf[LINE_LEN+1];
2479
2487
  load_line( line_buf, input_fp );
2480
2488
  parse_geometry_card_line(line_buf, gm, in_i1, in_i2, in_x1, in_y1, in_z1, in_x2, in_y2, in_z2, in_rad);
2481
2489
  }
@@ -2486,7 +2494,7 @@ void c_geometry::read_geometry_card(std::istream& is, char *gm,
2486
2494
  nec_float *in_x2, nec_float *in_y2, nec_float *in_z2,
2487
2495
  nec_float *in_rad )
2488
2496
  {
2489
- char line_buf[134];
2497
+ char line_buf[LINE_LEN+1];
2490
2498
  load_line( line_buf, is );
2491
2499
  parse_geometry_card_line(line_buf, gm, in_i1, in_i2, in_x1, in_y1, in_z1, in_x2, in_y2, in_z2, in_rad);
2492
2500
  }
@@ -330,8 +330,8 @@ void factrs(nec_output_file& s_output, int64_t np, int64_t nrow, complex_arra
330
330
  for (int mode = 0; mode < num_symmetric_modes; mode++ ) {
331
331
  int64_t mode_offset = mode * np;
332
332
 
333
- complex_array a_temp = a.segment(mode_offset, a.size()-mode_offset);
334
- int_array ip_temp = ip.segment(mode_offset, ip.size()-mode_offset);
333
+ complex_array a_temp = a.eigen_segment(mode_offset, a.size()-mode_offset);
334
+ int_array ip_temp = ip.eigen_segment(mode_offset, ip.size()-mode_offset);
335
335
 
336
336
  lu_decompose(s_output, np, a_temp, ip_temp, nrow );
337
337
  }
@@ -426,9 +426,9 @@ void solves(complex_array& a, int_array& ip, complex_array& b, int64_t neq,
426
426
 
427
427
  for (int64_t ic = 0; ic < nrh; ic++ ) {
428
428
  int64_t column_offset = ic*neq;
429
- complex_array a_sub = a.segment(ia, a.size()-ia);
430
- complex_array b_sub = b.segment(ia+column_offset, b.size() - (ia+column_offset) );
431
- int_array ip_sub = ip.segment(ia, ip.size()-ia);
429
+ complex_array a_sub = a.eigen_segment(ia, a.size()-ia);
430
+ complex_array b_sub = b.eigen_segment(ia+column_offset, b.size() - (ia+column_offset) );
431
+ int_array ip_sub = ip.eigen_segment(ia, ip.size()-ia);
432
432
  solve( npeq, a_sub, ip_sub, b_sub, nrow );
433
433
  }
434
434
  } /* for( kk = 0; kk < nop; kk++ ) */
@@ -119,8 +119,19 @@ int load_line( char *buff, FILE *pfile )
119
119
  buff[num_chr] = '\0';
120
120
  eof = EOF;
121
121
  }
122
- } /* end of while( num_chr < max_chr ) */
123
-
122
+ } /* end of while( num_chr < LINE_LEN ) */
123
+
124
+ /* drain any characters past LINE_LEN so an over-length line
125
+ * cannot leak its tail into the next load_line read. Match the
126
+ * fill loop's EOF convention (set eof, fall through) rather than
127
+ * the single-quote drain's early return, so the buffer's mnemonic
128
+ * is still capitalized/terminated and the caller sees EOF. */
129
+ while( (chr != CR) && (chr != LF) )
130
+ if( (chr = fgetc(pfile)) == EOF ) {
131
+ eof = EOF;
132
+ break;
133
+ }
134
+
124
135
  /* Capitalize first two characters (mnemonics) */
125
136
  buff[0] = static_cast<char>(std::toupper(buff[0]));
126
137
  buff[1] = static_cast<char>(std::toupper(buff[1]));
@@ -175,6 +186,17 @@ int load_line( char *buff, std::istream& is )
175
186
  }
176
187
  }
177
188
 
189
+ /* drain any characters past LINE_LEN so an over-length line
190
+ * cannot leak its tail into the next load_line read. Match the
191
+ * fill loop's EOF convention (set eof, fall through). */
192
+ while ( (chr != CR) && (chr != LF) ) {
193
+ chr = is.get();
194
+ if ( !is ) {
195
+ eof = EOF;
196
+ break;
197
+ }
198
+ }
199
+
178
200
  buff[0] = static_cast<char>(std::toupper(buff[0]));
179
201
  buff[1] = static_cast<char>(std::toupper(buff[1]));
180
202
  buff[num_chr] = '\0';
@@ -9,7 +9,7 @@
9
9
  #define LF 0x0a
10
10
 
11
11
  /* max length of a line read from input file */
12
- #define LINE_LEN 132
12
+ #define LINE_LEN 512
13
13
 
14
14
  /* usage()
15
15
  *
@@ -2111,7 +2111,7 @@ void nec_context::cmset( int64_t nrow, complex_array& in_cm, nec_float rkhx) {
2111
2111
  cmww( j, i1, in2, in_cm, nrow, in_cm, nrow,1);
2112
2112
 
2113
2113
  if ( im1 <= im2) {
2114
- complex_array temp = in_cm.segment((ist-1)*nrow, in_cm.size() - ((ist-1)*nrow));
2114
+ complex_array temp = in_cm.eigen_segment((ist-1)*nrow, in_cm.size() - ((ist-1)*nrow));
2115
2115
  cmws( j, im1, im2, temp, nrow, in_cm, nrow, 1);
2116
2116
  /* CMWS (J,IM1,IM2,CM(1,IST),NROW,CM,NROW,1) */
2117
2117
  }
@@ -2148,13 +2148,13 @@ void nec_context::cmset( int64_t nrow, complex_array& in_cm, nec_float rkhx) {
2148
2148
 
2149
2149
  if ( i1 <= in2) {
2150
2150
  int64_t tmp_n = (jst-1);
2151
- complex_array temp = in_cm.segment(tmp_n, in_cm.size()-tmp_n);
2151
+ complex_array temp = in_cm.eigen_segment(tmp_n, in_cm.size()-tmp_n);
2152
2152
  cmsw( jm1, jm2, i1, in2, temp, in_cm, 0, nrow, 1);
2153
2153
  }
2154
2154
 
2155
2155
  if ( im1 <= im2) {
2156
2156
  int64_t tmp_n = (jst-1)+(ist-1)*nrow;
2157
- complex_array temp = in_cm.segment(tmp_n, in_cm.size()-tmp_n);
2157
+ complex_array temp = in_cm.eigen_segment(tmp_n, in_cm.size()-tmp_n);
2158
2158
  compute_matrix_ss( jm1, jm2, im1, im2, temp, nrow, 1);
2159
2159
  }
2160
2160
  }
@@ -2177,7 +2177,7 @@ void nec_context::cmset( int64_t nrow, complex_array& in_cm, nec_float rkhx) {
2177
2177
  scm[k] = in_cm[row_offset + ka];
2178
2178
  }
2179
2179
 
2180
- in_cm[row_offset + j] = scm.segment(0,nop).sum(); //scm.sum(0,nop);
2180
+ in_cm[row_offset + j] = scm.eigen_segment(0,nop).sum(); //scm.sum(0,nop);
2181
2181
 
2182
2182
  for( int k = 1; k < nop; k++ ) {
2183
2183
  int ka = j+ k*npeq;
@@ -6819,14 +6819,14 @@ void nec_context::ffld(nec_float thet, nec_float phi,
6819
6819
  /* electric field components */
6820
6820
  roz= rozs;
6821
6821
  { // without ground
6822
- complex_array temp = current_vector.segment(m_geometry->n_segments, current_vector.size()-m_geometry->n_segments);
6822
+ complex_array temp = current_vector.eigen_segment(m_geometry->n_segments, current_vector.size()-m_geometry->n_segments);
6823
6823
  m_geometry->fflds(rox, roy, roz, temp, &ex, &ey, &ez);
6824
6824
  }
6825
6825
  if (ground.present()) {
6826
6826
  // with ground
6827
6827
  nec_complex tempx, tempy, tempz;
6828
6828
 
6829
- complex_array temp = current_vector.segment(m_geometry->n_segments, current_vector.size()-m_geometry->n_segments);
6829
+ complex_array temp = current_vector.eigen_segment(m_geometry->n_segments, current_vector.size()-m_geometry->n_segments);
6830
6830
  m_geometry->fflds(rox, roy, -roz, temp, &tempx, &tempy, &tempz);
6831
6831
 
6832
6832
  if (ground.type_perfect()) {
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "PyNEC"
8
- version = "2.2.1"
8
+ version = "2.2.2"
9
9
  description = "Python Antenna Simulation Module (nec2++) object-oriented interface"
10
10
  readme = "README.md"
11
11
  license = "GPL-3.0-only"
@@ -59,11 +59,11 @@ class TestInputParameters:
59
59
  def test_frequency_matches(self, simple_dipole):
60
60
  """Returned frequency should match the FR card."""
61
61
  ai = simple_dipole.get_input_parameters(0)
62
- freqs = ai.get_frequency()
62
+ # necpp returns the result's frequency as a scalar (Hz).
63
+ freq = ai.get_frequency()
63
64
 
64
- assert len(freqs) > 0
65
65
  # FR card set 200 MHz with 50 MHz step, 3 frequencies
66
- assert abs(freqs[0] - 200.0) < 1.0
66
+ assert abs(freq - 200.0e6) < 1.0e6
67
67
 
68
68
  def test_tag_and_segment(self, simple_dipole):
69
69
  """Tag and segment arrays should be non-empty."""
@@ -32,10 +32,10 @@ class TestNearField:
32
32
  assert nh is not None
33
33
 
34
34
  def test_electric_field_frequency(self, dipole_near_field):
35
- """Frequency should be non-empty."""
35
+ """Frequency should be set (scalar, Hz)."""
36
36
  ne = dipole_near_field.get_near_field_pattern(0)
37
- freqs = ne.get_frequency()
38
- assert len(freqs) > 0
37
+ freq = ne.get_frequency()
38
+ assert freq > 0
39
39
 
40
40
  def test_electric_field_coordinates(self, dipole_near_field):
41
41
  """X, Y, Z coordinate arrays should be non-empty."""
@@ -29,8 +29,9 @@ class TestNormRxPattern:
29
29
 
30
30
  def test_frequency(self, rx_antenna):
31
31
  nrp = rx_antenna.get_norm_rx_pattern(0)
32
- freqs = nrp.get_frequency()
33
- assert len(freqs) > 0
32
+ # necpp returns the result's frequency as a scalar (Hz).
33
+ freq = nrp.get_frequency()
34
+ assert freq > 0
34
35
 
35
36
  def test_theta_phi_counts(self, rx_antenna):
36
37
  """N_theta and N_phi should be non-negative."""
@@ -53,9 +54,10 @@ class TestNormRxPattern:
53
54
  assert nrp.get_axial_ratio() is not None
54
55
 
55
56
  def test_segment_number(self, rx_antenna):
56
- """Segment numbers should be non-empty."""
57
+ """Segment number should be set (scalar)."""
57
58
  nrp = rx_antenna.get_norm_rx_pattern(0)
58
- assert len(nrp.get_segment_number()) > 0
59
+ # necpp returns the segment number as a scalar int.
60
+ assert nrp.get_segment_number() > 0
59
61
 
60
62
  def test_magnitude(self, rx_antenna):
61
63
  """Magnitude should be non-empty."""
@@ -60,10 +60,14 @@ class TestPatches:
60
60
  assert len(sc.get_patch_e_z()) > 0
61
61
 
62
62
  def test_impedance_finite(self, cylinder_with_patches):
63
- """Impedance should be finite."""
63
+ """Impedance should be finite (no NaN/Inf)."""
64
+ import math
65
+
64
66
  ipt = cylinder_with_patches.get_input_parameters(0)
65
67
  z = ipt.get_impedance()
66
68
  assert len(z) > 0
69
+ # This patch model has a high (but finite) input impedance; the
70
+ # requirement is finiteness, not a magnitude bound.
67
71
  for val in z:
68
- assert abs(val.real) < 1e6
69
- assert abs(val.imag) < 1e6
72
+ assert math.isfinite(val.real)
73
+ assert math.isfinite(val.imag)
@@ -73,11 +73,12 @@ class TestRadiationPattern:
73
73
  assert rp.get_e_phi() is not None
74
74
 
75
75
  def test_frequency(self, radpat_dipole):
76
- """Frequency should be a non-empty array."""
76
+ """Frequency should be set (scalar, Hz)."""
77
77
  rp = radpat_dipole.get_radiation_pattern(0)
78
- freqs = rp.get_frequency()
78
+ # necpp returns the result's frequency as a scalar.
79
+ freq = rp.get_frequency()
79
80
 
80
- assert len(freqs) > 0
81
+ assert freq > 0
81
82
 
82
83
  def test_gain_max_is_finite(self, radpat_dipole):
83
84
  """Gain max should be finite and not NaN."""
@@ -29,10 +29,11 @@ class TestStructureCurrents:
29
29
  assert sc is not None
30
30
 
31
31
  def test_frequency(self, dipole_with_currents):
32
- """Frequency should be non-empty."""
32
+ """Frequency should be set (scalar, Hz)."""
33
33
  sc = dipole_with_currents.get_structure_currents(0)
34
- freqs = sc.get_frequency()
35
- assert len(freqs) > 0
34
+ # necpp returns the result's frequency as a scalar.
35
+ freq = sc.get_frequency()
36
+ assert freq > 0
36
37
 
37
38
  def test_segment_info(self, dipole_with_currents):
38
39
  """Segment number, tag, center, length should be non-empty."""
@@ -50,10 +51,15 @@ class TestStructureCurrents:
50
51
  assert len(curr) > 0
51
52
 
52
53
  def test_current_theta_phi(self, dipole_with_currents):
53
- """Theta and phi components should be non-empty."""
54
+ """Theta and phi components are populated for patch (m>0) models.
55
+
56
+ Wire-only models (m == 0) have no patch currents, so these arrays
57
+ are legitimately empty; only assert non-empty when patches exist.
58
+ """
54
59
  sc = dipole_with_currents.get_structure_currents(0)
55
- assert len(sc.get_current_theta()) > 0
56
- assert len(sc.get_current_phi()) > 0
60
+ if sc.get_m() > 0:
61
+ assert len(sc.get_current_theta()) > 0
62
+ assert len(sc.get_current_phi()) > 0
57
63
 
58
64
  def test_n_m_counts(self, dipole_with_currents):
59
65
  """N and M counts should be non-negative."""
@@ -64,6 +70,7 @@ class TestStructureCurrents:
64
70
  def test_ipt_flags(self, dipole_with_currents):
65
71
  """IPT flags should be valid."""
66
72
  sc = dipole_with_currents.get_structure_currents(0)
67
- # iptflg and iptflq are print flags, should be >= 0
68
- assert sc.get_iptflg() >= 0
69
- assert sc.get_iptflq() >= 0
73
+ # iptflg and iptflq are print flags. -1 is the necpp sentinel for
74
+ # "no print flag set" (e.g. no patch currents), so allow >= -1.
75
+ assert sc.get_iptflg() >= -1
76
+ assert sc.get_iptflq() >= -1
@@ -47,10 +47,11 @@ class TestStructureExcitation:
47
47
  assert se is not None
48
48
 
49
49
  def test_frequency(self, log_periodic):
50
- """Frequency should be a non-empty array."""
50
+ """Frequency should be set (scalar, Hz)."""
51
51
  se = log_periodic.get_structure_excitation(0)
52
- freqs = se.get_frequency()
53
- assert len(freqs) > 0
52
+ # necpp returns the result's frequency as a scalar.
53
+ freq = se.get_frequency()
54
+ assert freq > 0
54
55
 
55
56
  def test_tag_and_segment(self, log_periodic):
56
57
  """Tag and segment arrays should be non-empty."""
@@ -67,9 +68,17 @@ class TestStructureExcitation:
67
68
  assert len(voltage) > 0
68
69
 
69
70
  def test_power_non_negative(self, log_periodic):
70
- """Power should be non-negative."""
71
+ """Power values should be finite.
72
+
73
+ This log-periodic array is strongly coupled through transmission
74
+ lines, so individual elements exchange power and the per-element
75
+ values can be negative or sum to ~0 (a near-reactive solution).
76
+ The meaningful invariant is that the values are finite numbers.
77
+ """
78
+ import math
79
+
71
80
  se = log_periodic.get_structure_excitation(0)
72
81
  power = se.get_power()
73
82
  assert len(power) > 0
74
83
  for p in power:
75
- assert p >= 0
84
+ assert math.isfinite(p)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes