GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Some additional cards ported to the cleaner context API · saharbin/python-necpp@65601c1

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • PyNECPP/example
    • antenna_util.py
    • context_clean.py
  • README.md
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎PyNECPP/example/antenna_util.py‎

Copy file name to clipboardExpand all lines: PyNECPP/example/antenna_util.py
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,27 @@
55

66
def reflection_coefficient(z, z0):
77
return np.abs((z - z0) / (z + z0))
8+
9+
def vswr(z, z0):
10+
Gamma = reflection_coefficient(z, z0)
11+
return float((1 + Gamma) / (1 - Gamma))
12+
13+
def mismatch(z, z0):
14+
Gamma = reflection_coefficient(z, z0)
15+
return 1 - Gamma**2
16+
17+
# Source: https://gist.github.com/temporaer/6755266
18+
# 'matplotlib log-polar plots seem to be quite buggy at the time of writing.' Yes, indeed, sadly...
19+
def plot_logpolar(ax, theta, r_, bullseye=None, **kwargs):
20+
min10 = np.log10(np.min(r_))
21+
max10 = np.log10(np.max(r_))
22+
if bullseye is None:
23+
bullseye = min10 - np.log10(0.5 * np.min(r_))
24+
r = np.log10(r_) - min10 + bullseye
25+
ax.plot(theta, r, **kwargs)
26+
l = np.arange(np.floor(min10), max10)
27+
ax.set_rticks(l - min10 + bullseye)
28+
# ax.set_yticklabels(["1e%d" % x for x in l])
29+
ax.set_yticklabels(["%d" % x for x in l])
30+
ax.set_rlim(0, max10 - min10 + bullseye)
31+
return ax
Collapse file

‎PyNECPP/example/context_clean.py‎

Copy file name to clipboardExpand all lines: PyNECPP/example/context_clean.py
+96-3Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@
22

33
# Currently these contain only the subset of cards that I needed
44

5+
class Range(object):
6+
def __init__(self, start, stop, count=None, delta=None):
7+
self.start = start
8+
self.stop = stop
9+
if count is not None:
10+
self.count = count
11+
self.delta = (stop - start) / count
12+
else:
13+
self.count = (stop_ - start) / delta
14+
self.delta = delta
15+
16+
# Setting do_debug to True will dump all the cards generated with context_clean, so you can verify the output more easily in a text editor (and debug that file manually)
17+
do_debug = False
18+
19+
def debug(card, *args):
20+
if do_debug:
21+
stringified = " , ".join([str(a) for a in args])
22+
print "%s %s" % (card, stringified)
23+
524
class context_clean(object):
625
def __init__(self, context):
726
self.context = context
@@ -14,6 +33,8 @@ def set_wire_conductivity(self, conductivity, wire_tag=None):
1433
""" The conductivity is specified in mhos/meter. Currently all segments of a wire are set. If wire_tag is None, all wire_tags are set (i.e., a tag of 0 is used). """
1534
if wire_tag is None:
1635
wire_tag = 0
36+
37+
debug("LD", 5, wire_tag, 0, 0, conductivity, 0, 0)
1738
self.context.ld_card(5, wire_tag, 0, 0, conductivity, 0, 0)
1839

1940
def set_all_wires_conductivity(self, conductivity):
@@ -37,6 +58,7 @@ def set_frequencies_linear(self, start_frequency, stop_frequency, count=None, st
3758
count = int(count)
3859

3960
ifrq_linear_step = 0
61+
debug("FR", ifrq_linear_step, count, start_frequency, step_size, 0, 0, 0)
4062
self.context.fr_card(ifrq_linear_step, count, start_frequency, step_size)
4163

4264
def set_frequency(self, frequency):
@@ -46,19 +68,30 @@ def clear_ground(self):
4668
gn_nullify_ground = -1
4769
self.context.gn_card(gn_nullify_ground, 0, 0, 0, 0, 0, 0, 0)
4870

71+
# TODO: I could probably make a ground class, would probably be cleaner to group some of the options and different functions there (like combining ground screen etc)
72+
4973
# TODO: gn card is iffy, check!
5074
def set_finite_ground(self, ground_dielectric, ground_conductivity):
5175
gn_finite_ground = 0
5276
no_ground_screen = 0
5377

5478
self.context.gn_card(gn_finite_ground, no_ground_screen, ground_dielectric, ground_conductivity, 0, 0, 0, 0)
5579

80+
def set_perfect_ground(self):
81+
gn_perfectly_conducting = 1
82+
no_ground_screen = 0
83+
84+
debug("GN", gn_perfectly_conducting, no_ground_screen, 0, 0, 0, 0, 0, 0)
85+
self.context.gn_card(gn_perfectly_conducting, no_ground_screen, 0, 0, 0, 0, 0, 0)
86+
87+
5688
# TODO: i1 = 5 is also a voltage excitation
5789
def voltage_excitation(self, wire_tag, segment_nr, voltage):
5890
ex_voltage_excitation = 0
5991
no_action = 0 # TODO configurable
6092
option_i3i4 = 10*no_action + no_action
6193

94+
debug("EX", ex_voltage_excitation, wire_tag, segment_nr, option_i3i4, voltage.real, voltage.imag, 0, 0, 0, 0)
6295
self.context.ex_card(ex_voltage_excitation, wire_tag, segment_nr, option_i3i4, voltage.real, voltage.imag, 0, 0, 0, 0)
6396

6497
def get_geometry(self):
@@ -67,16 +100,74 @@ def get_geometry(self):
67100

68101
def set_extended_thin_wire_kernel(self, enable):
69102
if enable:
103+
debug ("EK", 0)
70104
self.context.set_extended_thin_wire_kernel(1)
71105
else:
106+
debug ("EK", -1)
72107
self.context.set_extended_thin_wire_kernel(0)
73108

109+
def geometry_complete(self, ground_plane, current_expansion=True):
110+
no_ground_plane = 0
111+
ground_plane_current_expansion = 1
112+
ground_plane_no_current_expansion = -1
113+
if not ground_plane:
114+
debug("GE", no_ground_plane)
115+
self.context.geometry_complete(no_ground_plane)
116+
else:
117+
if current_expansion:
118+
debug("GE", ground_plane_current_expansion)
119+
self.context.geometry_complete(ground_plane_current_expansion)
120+
else:
121+
debug("GE", ground_plane_no_current_expansion)
122+
self.context.geometry_complete(ground_plane_no_current_expansion)
123+
124+
output_major_minor = 0
125+
output_vertical_horizontal = 1
126+
127+
normalization_none = 0
128+
normalization_major = 1
129+
normalization_minor = 2
130+
normalization_vertical = 3
131+
normalization_horizontal = 4
132+
normalization_totalgain = 5
133+
134+
power_gain = 0
135+
directive_gain = 1
136+
137+
average_none = 0
138+
average_gain = 1
139+
average_todo = 2
140+
141+
# TODO: this should be different for surface_wave_mode (1), because then thetas = z
142+
def radiation_pattern(self, thetas, phis, output_mode=output_vertical_horizontal, normalization=normalization_none, gain=power_gain, average=average_todo):
143+
""" thetas and phis should be Range(-like) objects """
144+
normal_mode = 0 # TODO other modes
145+
146+
# the rp_card already has XNDA as separate arguments
147+
radial_distance = 0 # TODO
148+
gnornamize_maximum = 0 # TODO
149+
150+
xnda = average + 10*gain+100*normalization+1000*output_mode
151+
152+
debug("RP", normal_mode, thetas.count, phis.count, xnda, thetas.start, phis.start, thetas.delta, phis.delta, radial_distance, gnornamize_maximum)
153+
self.context.rp_card(normal_mode, thetas.count, phis.count, output_mode, normalization, gain, average, thetas.start, phis.start, thetas.delta, phis.delta, radial_distance, gnornamize_maximum)
154+
155+
# TODO: shunt admittances, length of transmission line if not straight-line distance
156+
def transmission_line(self, src, dst, impedance, crossed_line=False, length=None, shunt_admittance_src=0, shunt_admittance_dst=0):
157+
""" src and dst are (tag_nr, segment_nr) pairs """
158+
if crossed_line:
159+
impedance *= -1
160+
if length is None:
161+
length = 0
162+
shunt_admittance_src = complex(shunt_admittance_src)
163+
shunt_admittance_dst = complex(shunt_admittance_dst)
164+
165+
debug("TL", src[0], src[1], dst[0], dst[1], impedance, length, shunt_admittance_src.real, shunt_admittance_src.imag, shunt_admittance_dst.real, shunt_admittance_dst.imag)
166+
self.context.tl_card(src[0], src[1], dst[0], dst[1], impedance, length, shunt_admittance_src.real, shunt_admittance_src.imag, shunt_admittance_dst.real, shunt_admittance_dst.imag)
167+
74168
# Some simple wrappers for context...
75169
# TODO: this should be simpler, can't this be auto-generated, or implicitly defined? The best solution is of course to do this in the C++ code,
76170
# and then the wrappers are immediately correct and nice
77-
78-
def geometry_complete(self, *args):
79-
return self.context.geometry_complete(*args)
80171
def xq_card(self, *args):
81172
return self.context.xq_card(*args)
82173
def get_input_parameters(self, *args):
@@ -88,4 +179,6 @@ def __init__(self, geometry):
88179

89180
def wire(self, tag_id, nr_segments, src, dst, radius, length_ratio=1.0, radius_ratio=1.0):
90181
""" radius is in meter. length_ratio can be set to have non-uniform segment lengths, radius_ratio can be used for tapered wires """
182+
debug("GW", tag_id, nr_segments, src[0], src[1], src[2], dst[0], dst[1], dst[2], radius) # TODO
183+
91184
self.geometry.wire(tag_id, nr_segments, src[0], src[1], src[2], dst[0], dst[1], dst[2], radius, length_ratio, radius_ratio)
Collapse file

‎README.md‎

Copy file name to clipboardExpand all lines: README.md
+6-4Lines changed: 6 additions & 4 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
This repository contains two wrappers for the nec2++ antenna simulation package:
44

5-
* PyNEC/ contains a wrapper using SWIG of the C interface (Python module name: necpp)
6-
* PyNECPP/ contains a wrapper of the C++ interfaces (Python module name: PyNEC).
5+
* PyNEC/ contains a wrapper using SWIG of the C interface (Python module name: necpp).
6+
* PyNECPP/ contains a wrapper of the C++ interfaces (Python module name: PyNEC). The example/ directory furthermore contains some nicer, more readable Python wrappers that make toying around with NEC a less painful experience.
77

88
Both are based on Tim Molteno ([email protected])'s code.
99

10-
Personally, I (Bart Coppens, [email protected]) am more interested in a slightly cleaned-up version of the C++ interface wrappers. (I might still rename the Python module names to match the directory names, or rename the directories, or both)
10+
Personally, I (Bart Coppens, [email protected]) am more interested in a slightly cleaned-up version of the C++ interface wrappers. (I might still rename the Python module names to match the directory names, or rename the directories, or both). In particular, as mentioned above, PyNECPP/example contains context_clean.py, which separates some of the NEC cards with multiple options into multiple functions (with named arguments that make sense, rather than itmp1, itmp2, etc). I've only really done this for the code I was playing around with in the example/ subdirectory, though, lots of cards (and sub-functionalities of cards) remain unwrapped/unported. Still, I found it to be nicer.
11+
12+
PyNECPP/example/logperiodic.py furthermore contains an example on how to combine PyNECPP with scipy.optimize to use a genetic algorithm to **optimize an antenna for multiple frequency bands** at the same time (which I thin is not possible in 4nec2).
1113

1214
## TODOs
13-
The cleaner API should really be ported to C++, so the clean wrappers get automatically generated, and C++ can use the same cleaner interface
15+
The cleaner API should really be **ported to C++**, so the clean wrappers get automatically generated, and C++ can use the same cleaner interface. But for now, I'm happy with the Python wrapper :)

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.