emsutil 0.2.2__tar.gz → 0.3.0__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 (33) hide show
  1. {emsutil-0.2.2 → emsutil-0.3.0}/.bumpversion.toml +1 -1
  2. {emsutil-0.2.2 → emsutil-0.3.0}/PKG-INFO +1 -1
  3. emsutil-0.3.0/emerge-install-mumps +32 -0
  4. {emsutil-0.2.2 → emsutil-0.3.0}/pyproject.toml +1 -1
  5. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/emdata.py +15 -12
  6. emsutil-0.3.0/src/emsutil/inexport/ffdata.py +304 -0
  7. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/themes.py +58 -0
  8. {emsutil-0.2.2 → emsutil-0.3.0}/uv.lock +1 -1
  9. emsutil-0.2.2/src/emsutil/inexport/ffdata.py +0 -58
  10. {emsutil-0.2.2 → emsutil-0.3.0}/.gitignore +0 -0
  11. {emsutil-0.2.2 → emsutil-0.3.0}/.python-version +0 -0
  12. {emsutil-0.2.2 → emsutil-0.3.0}/README.md +0 -0
  13. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/__init__.py +0 -0
  14. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/const.py +0 -0
  15. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/inexport/strutil.py +0 -0
  16. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/isola.py +0 -0
  17. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/lib.py +0 -0
  18. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/material.py +0 -0
  19. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/plot/__init__.py +0 -0
  20. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/plot/plot2d.py +0 -0
  21. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/__init__.py +0 -0
  22. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/cmap_maker.py +0 -0
  23. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/display.py +0 -0
  24. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/display_settings.py +0 -0
  25. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/background.png +0 -0
  26. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex1.png +0 -0
  27. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex2.png +0 -0
  28. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex3.png +0 -0
  29. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex4.png +0 -0
  30. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex5.png +0 -0
  31. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex6.png +0 -0
  32. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/utils.py +0 -0
  33. {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/rogers.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [tool.bumpversion]
2
- current_version = "0.2.2"
2
+ current_version = "0.3.0"
3
3
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
4
4
  serialize = ["{major}.{minor}.{patch}"]
5
5
  search = "{current_version}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emsutil
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Common utilities for Emerge projects EMerge, Optycal and Heavi
5
5
  Project-URL: Homepage, https://github.com/FennisRobert/emsutil
6
6
  Project-URL: Issues, https://github.com/FennisRobert/emsutil/issues
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # Resolve Python environment
5
+ PYTHON="$(command -v python)"
6
+
7
+ if [ -z "$PYTHON" ]; then
8
+ echo "ERROR: No active Python environment found."
9
+ exit 1
10
+ fi
11
+
12
+ echo "Using Python:"
13
+ echo " $PYTHON"
14
+
15
+ # Location of bundled installer
16
+ INSTALLER_ROOT="$HOME/.emerge/installer"
17
+
18
+ if [ ! -f "$INSTALLER_ROOT/install.sh" ]; then
19
+ echo "ERROR: MUMPS installer not found."
20
+ echo "Expected:"
21
+ echo " $INSTALLER_ROOT/install.sh"
22
+ exit 1
23
+ fi
24
+
25
+ # Run installer
26
+ bash "$INSTALLER_ROOT/install.sh"
27
+
28
+ # Install Python package into *this* environment
29
+ "$PYTHON" -m pip install "$HOME/.emerge/mumps_py"
30
+
31
+ echo
32
+ echo "MUMPS successfully installed for this Python environment."
@@ -4,7 +4,7 @@ allow-direct-references = true
4
4
 
5
5
  [project]
6
6
  name = "emsutil"
7
- version = "0.2.2"
7
+ version = "0.3.0"
8
8
  description = "Common utilities for Emerge projects EMerge, Optycal and Heavi"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -7,6 +7,8 @@ from .lib import EISO, EOMNI
7
7
  @dataclass
8
8
  class FarFieldComponent:
9
9
  F: np.ndarray
10
+ _th: np.ndarray
11
+ _ph: np.ndarray
10
12
 
11
13
  @property
12
14
  def x(self) -> np.ndarray:
@@ -22,16 +24,16 @@ class FarFieldComponent:
22
24
 
23
25
  @property
24
26
  def theta(self) -> np.ndarray:
25
- thx = np.cos(self.theta)*np.cos(self.phi)
26
- thy = np.cos(self.theta)*np.sin(self.phi)
27
- thz = -np.sin(self.theta)
27
+ thx = np.cos(self._th)*np.cos(self._ph)
28
+ thy = np.cos(self._th)*np.sin(self._ph)
29
+ thz = -np.sin(self._th)
28
30
  return thx*self.F[0,:] + thy*self.F[1,:] + thz*self.F[2,:]
29
31
 
30
32
  @property
31
33
  def phi(self) -> np.ndarray:
32
- phx = -np.sin(self.phi)
33
- phy = np.cos(self.phi)
34
- phz = np.zeros_like(self.theta)
34
+ phx = -np.sin(self._ph)
35
+ phy = np.cos(self._ph)
36
+ phz = np.zeros_like(self._th)
35
37
  return phx*self.F[0,:] + phy*self.F[1,:] + phz*self.F[2,:]
36
38
 
37
39
  @property
@@ -122,6 +124,7 @@ class EHFieldFF:
122
124
  phi: np.ndarray
123
125
  Ptot: float
124
126
  ang: np.ndarray | None = field(default=None)
127
+ freq: float | None = field(default=None)
125
128
 
126
129
  def total_radiated_power_integral(
127
130
  self,
@@ -183,11 +186,11 @@ class EHFieldFF:
183
186
 
184
187
  @property
185
188
  def E(self) -> np.ndarray:
186
- return FarFieldComponent(self._E)
189
+ return FarFieldComponent(self._E, self.theta, self.phi)
187
190
 
188
191
  @property
189
192
  def H(self) -> np.ndarray:
190
- return FarFieldComponent(self._H)
193
+ return FarFieldComponent(self._H, self.theta, self.phi)
191
194
 
192
195
  @property
193
196
  def Ex(self) -> np.ndarray:
@@ -244,16 +247,16 @@ class EHFieldFF:
244
247
  @property
245
248
  def gain(self, kind: Literal['iso','omni'] = 'iso') -> FarFieldComponent:
246
249
  if kind=='iso':
247
- return FarFieldComponent(self._E/EISO)
250
+ return FarFieldComponent(self._E/EISO, self.theta, self.phi)
248
251
  else:
249
- return FarFieldComponent(self._E/EOMNI)
252
+ return FarFieldComponent(self._E/EOMNI, self.theta, self.phi)
250
253
 
251
254
  @property
252
255
  def dir(self, kind: Literal['iso','omni'] = 'iso') -> FarFieldComponent:
253
256
  if kind=='iso':
254
- return FarFieldComponent(self._E/(EISO*(self.Ptot)**0.5))
257
+ return FarFieldComponent(self._E/(EISO*(self.Ptot)**0.5), self.theta, self.phi)
255
258
  else:
256
- return FarFieldComponent(self._E/(EOMNI*(self.Ptot)**0.5))
259
+ return FarFieldComponent(self._E/(EOMNI*(self.Ptot)**0.5), self.theta, self.phi)
257
260
 
258
261
  @property
259
262
  def normE(self) -> np.ndarray:
@@ -0,0 +1,304 @@
1
+ import numpy as np
2
+ from .strutil import arry_to_line, matrix_to_lines, arry_to_fwl
3
+ from ..emdata import EHFieldFF
4
+ from dataclasses import dataclass
5
+ from typing import List
6
+ from loguru import logger
7
+ import os
8
+
9
+ @dataclass
10
+ class Column:
11
+ name: str
12
+ values: np.ndarray
13
+
14
+ @staticmethod
15
+ def from_array(name: str, data: np.ndarray) -> List["Column"]:
16
+ """
17
+ Returns:
18
+ - [Column] if data is real
19
+ - [Column(real), Column(imag)] if data is complex
20
+ """
21
+ data = np.asarray(data)
22
+
23
+ if np.iscomplexobj(data):
24
+ return [
25
+ Column(f"{name}[re]", data.real),
26
+ Column(f"{name}[im]", data.imag),
27
+ ]
28
+ else:
29
+ return [Column(name, data)]
30
+
31
+
32
+ def to_lines(
33
+ columns: List[Column],
34
+ header_prefix: str = "$ ",
35
+ separator: str = " ",
36
+ fmt: str = "{:g}",
37
+ ) -> List[str]:
38
+ """
39
+ Convert columns to equally spaced text lines.
40
+ """
41
+
42
+ # Convert all values to strings first
43
+ str_cols = [[fmt.format(v) for v in col.values] for col in columns]
44
+ headers = [col.name for col in columns]
45
+ headers[0] = header_prefix + headers[0]
46
+ for i in range(len(headers)-1):
47
+ headers[i] = headers[i] + ';'
48
+ # Compute column widths (including separator!)
49
+ widths = []
50
+ for h, col in zip(headers, str_cols):
51
+ widths.append(max(len(h), max(len(v) for v in col)))
52
+
53
+ def format_row(items, sep: str):
54
+ return sep.join(item.ljust(w) for item, w in zip(items, widths))
55
+
56
+ lines = []
57
+
58
+ # Header
59
+ lines.append(format_row(headers, separator))
60
+
61
+ # Data rows
62
+ nrows = len(columns[0].values)
63
+ for i in range(nrows):
64
+ row = [col[i] for col in str_cols]
65
+ lines.append(format_row(row, separator))
66
+
67
+ return lines
68
+
69
+ class _fieldGetter:
70
+
71
+ def __init__(self, fields: list[EHFieldFF]):
72
+ self.names: list[str] = []
73
+ self.data: list = fields
74
+
75
+ @property
76
+ def name(self) -> str:
77
+ return '.'.join([n.capitalize() for n in self.names])
78
+
79
+ def __getattr__(self, name: str) -> EHFieldFF:
80
+ self.names.append(name)
81
+ self.data = [getattr(item, name) for item in self.data]
82
+ return self
83
+
84
+ class FarFieldExporter:
85
+ """A class to export far-field data to a text file.
86
+
87
+ """
88
+ def __init__(self, filename: str, fields: list[EHFieldFF], precision: int = 4, todeg: bool = True):
89
+ self.filename: str = filename
90
+ self.fields: list[EHFieldFF] = fields
91
+ self.precision: int = precision
92
+ self.columns: list[_fieldGetter] = []
93
+ self.todeg: bool = todeg
94
+
95
+ def addcol(self) -> EHFieldFF:
96
+ """Returns a field getter to specify which field component to export.
97
+
98
+ Example:
99
+ >>> exporter = FarFieldExporter('data.txt', field_data)
100
+ >>> exporter.addcol().Ex
101
+ >>> exporter.addcol().gain.theta
102
+ >>> exporter.write()
103
+
104
+ Returns:
105
+ EHFieldFF(_fieldGetter): Field getter to specify field component.
106
+ """
107
+ getter = _fieldGetter(self.fields)
108
+ self.columns.append(getter)
109
+ return getter
110
+
111
+ def write(self) -> None:
112
+ """Saves the far-field data to a text file.
113
+ """
114
+ base = self.fields[0]
115
+
116
+ thetas = base.theta
117
+ phis = base.phi
118
+
119
+ theta_lin = thetas[0,:].flatten()
120
+ phi_lin = phis[:,0].flatten()
121
+ p = self.precision
122
+ mult = 1.0
123
+ unit = 'rad'
124
+ if self.todeg:
125
+ mult = 180.0 / np.pi
126
+ theta_lin = theta_lin * mult
127
+ phi_lin = phi_lin * mult
128
+ thetas = thetas * mult
129
+ phis = phis * mult
130
+ unit = 'deg'
131
+
132
+ datalines = []
133
+ datalines.append(f'% Theta({unit})')
134
+ datalines.append(' '.join([f'{x:.{p}g}' for x in theta_lin]))
135
+ datalines.append(f'% Phi({unit})')
136
+ datalines.append(' '.join([f'{x:.{p}g}' for x in phi_lin]))
137
+ datalines.append('% Frequencies(Hz)')
138
+ datalines.append(' '.join([f'{field.freq:.{p}g}' for field in self.fields]))
139
+ datalines.append('')
140
+ thcol = Column(f'Theta({unit})', thetas.flatten())
141
+ phcol = Column(f'Phi({unit})', phis.flatten())
142
+
143
+ for i, field in enumerate(self.fields):
144
+ freq = field.freq
145
+ cols = []
146
+ datalines.append(f'# {freq:.{p}g} Hz')
147
+ for col in self.columns:
148
+ cols.extend(Column.from_array(col.name, col.data[i].flatten()))
149
+
150
+ datalines.extend(to_lines([thcol, phcol] + cols, fmt=f"{{:.{p}g}}"))
151
+ datalines.append('')
152
+
153
+ #replace any extension of filename with.emff
154
+ filename = os.path.splitext(self.filename)[0] + '.emff'
155
+ self.filename = filename
156
+ with open(self.filename, 'w') as f:
157
+ f.write('\n'.join(datalines))
158
+ logger.info(f'Wrote far-field data to {self.filename}')
159
+
160
+ def import_farfield(filename: str, degrees: bool = True) -> dict[str, np.ndarray]:
161
+ """Reads emerge farfiel datafiles created by FarFieldExporter.
162
+ They can be recognized by the .emff extension.
163
+
164
+ Args:
165
+ filename (str): The path to the far-field data file.
166
+ degrees (bool): If True, theta and phi angles are converted to degrees.
167
+
168
+ Returns:
169
+ dict[str, np.ndarray]: The imported far-field data structured as:
170
+ {
171
+ "theta": np.ndarray, # Theta grid (nTheta, nPhi)
172
+ "phi": np.ndarray, # Phi grid (nTheta, nPhi)
173
+ "freq": np.ndarray, # Frequencies (nF,)
174
+ "Ex": np.ndarray, # Electric field component Ex (nF, nTheta, nPhi)
175
+ "Ey": np.ndarray, # Electric field component Ey (nF, nTheta, nPhi)
176
+ ...
177
+ """
178
+ with open(filename, "r") as f:
179
+ lines = f.readlines()
180
+
181
+ # ---------------- helpers ----------------
182
+ def parse_vector(header):
183
+ i = lines.index(header) + 1
184
+ return np.array(lines[i].split(), float)
185
+
186
+ def strip_unit(name):
187
+ if "(" in name and ")" in name:
188
+ base, unit = name.split("(")
189
+ return base.strip(), unit.rstrip(")")
190
+ return name.strip(), None
191
+
192
+ def to_rad(values, unit):
193
+ if unit == "deg":
194
+ return np.deg2rad(values)
195
+ return values
196
+
197
+ # ---------------- global grids ----------------
198
+ theta_name, theta_unit = strip_unit("% Theta(deg)")
199
+ phi_name, phi_unit = strip_unit("% Phi(deg)")
200
+
201
+ # Find actual headers (deg or rad)
202
+ theta_header = next(l for l in lines if l.startswith("% Theta"))
203
+ phi_header = next(l for l in lines if l.startswith("% Phi"))
204
+
205
+ theta_vals = parse_vector(theta_header)
206
+ phi_vals = parse_vector(phi_header)
207
+ freqs = parse_vector("% Frequencies(Hz)\n")
208
+
209
+ theta_unit = theta_header.split("(")[1].split(")")[0]
210
+ phi_unit = phi_header.split("(")[1].split(")")[0]
211
+
212
+ theta_vals = to_rad(theta_vals, theta_unit)
213
+ phi_vals = to_rad(phi_vals, phi_unit)
214
+
215
+ nTheta = len(theta_vals)
216
+ nPhi = len(phi_vals)
217
+ nF = len(freqs)
218
+
219
+ theta_grid, phi_grid = np.meshgrid(theta_vals, phi_vals, indexing="ij")
220
+
221
+ result = {
222
+ "theta": theta_grid,
223
+ "phi": phi_grid,
224
+ "freq": freqs,
225
+ }
226
+
227
+ # ---------------- frequency blocks ----------------
228
+ field_buffers = {}
229
+ column_map = {}
230
+ header_info = {}
231
+ fidx = -1
232
+ header_cols = None
233
+ data_rows = []
234
+
235
+ for line in lines:
236
+ line = line.strip()
237
+ if not line:
238
+ continue
239
+
240
+ # Frequency block
241
+ if line.startswith("#"):
242
+ fidx += 1
243
+ data_rows = []
244
+ continue
245
+
246
+ # Header line
247
+ if line.startswith("$"):
248
+ header_cols = []
249
+ column_map.clear()
250
+ header_info.clear()
251
+
252
+ raw_cols = line[1:].split(";")
253
+ for i, raw in enumerate(raw_cols):
254
+ name, unit = strip_unit(raw)
255
+ header_cols.append(name)
256
+ header_info[name] = unit
257
+
258
+ if "[" in name and "]" in name:
259
+ base, comp = name.split("[")
260
+ comp = comp.rstrip("]")
261
+ column_map.setdefault(base, {})[comp] = i
262
+ else:
263
+ column_map[name] = i
264
+ continue
265
+
266
+ if line.startswith("%"):
267
+ continue
268
+
269
+ parts = line.split()
270
+ if header_cols is None or len(parts) < len(header_cols):
271
+ continue
272
+
273
+ data_rows.append([float(p) for p in parts])
274
+
275
+ if len(data_rows) == nTheta * nPhi:
276
+ data = np.array(data_rows)
277
+
278
+ for field, comps in column_map.items():
279
+ unit = header_info.get(field)
280
+
281
+ if isinstance(comps, dict): # complex
282
+ re = data[:, comps["re"]]
283
+ im = data[:, comps["im"]]
284
+ arr = re + 1j * im
285
+ else: # real
286
+ arr = data[:, comps]
287
+
288
+ if unit in ("deg", "rad"):
289
+ arr = to_rad(arr, unit)
290
+
291
+ arr = arr.reshape(nTheta, nPhi)
292
+ field_buffers.setdefault(field, []).append(arr)
293
+
294
+
295
+ # Stack frequencies
296
+ for field, blocks in field_buffers.items():
297
+ result[field] = np.stack(blocks, axis=0)
298
+
299
+ if degrees:
300
+ result["theta"] = np.rad2deg(result["theta"])
301
+ result["phi"] = np.rad2deg(result["phi"])
302
+ result["Theta"] = np.rad2deg(result["Theta"])
303
+ result["Phi"] = np.rad2deg(result["Phi"])
304
+ return result
@@ -184,8 +184,66 @@ class _Document(EMergeTheme):
184
184
  "#4DBEEEFF",
185
185
  ]
186
186
 
187
+ class Stylish(EMergeTheme):
188
+ """ A custom EMerge theme. """
189
+ def define(self):
190
+ self.backgroung_grad_1 = "#FFFFFF"
191
+ self.backgroung_grad_2 = "#FFFFFF"
192
+ self.grid_color = "#676767FF"
193
+ self.brightness = 1.0
194
+
195
+ self.label_color = "#FFFFFF"
196
+ self.text_color = "#000000FF"
197
+ self.render_metal = True
198
+ self.line_width = 3.0
199
+
200
+ self.geo_edge_width = 3.0
201
+ self.geo_edge_color = "#000000ff"
202
+
203
+
204
+ self.draw_xax = False
205
+ self.draw_yax = False
206
+ self.draw_zax = False
207
+ self.draw_xplane = False
208
+ self.draw_yplane = False
209
+ self.draw_zplane = False
210
+ self.draw_xgrid = False
211
+ self.draw_ygrid = False
212
+ self.draw_zgrid = False
213
+
214
+ self.axis_x_color = "#FF0000FF"
215
+ self.axis_y_color = "#00FF00FF"
216
+ self.axis_z_color = "#0000FFFF"
187
217
 
218
+ self.aa_active = True
219
+ self.aa_samples = 5
220
+ self.cmap_npts = 64
221
+
222
+ self.draw_pvgrid = False
223
+ self.render_shadows = True
224
+ # Basic clear academic scales
225
+ # Amplitude is Jet
226
+ # Wave is blue to transparent to red
227
+
228
+ self.colormaps = {
229
+ 'amplitude': (("#0000FF", "#00FFFF", "#00FF00", "#FFFF00", "#FF0000"),(0.0, 0.25, 0.5, 0.75, 1.0)),
230
+ 'wave': (("#FF0000", "#FFAAAA00","#0000FF00", "#0000FF"), (0.0, 0.49, 0.51, 1.0)),
231
+ }
232
+
233
+ self.render_style = 'surface'
234
+
235
+ # Clear high contrast matlab colors for paper
236
+ self.line_color_cycle = [
237
+ "#0072BDFF",
238
+ "#D95319FF",
239
+ "#EDB120FF",
240
+ "#7E2F8EFF",
241
+ "#77AC30FF",
242
+ "#4DBEEEFF",
243
+ ]
244
+
188
245
  VaporWave = _VaporWave()
189
246
  Vintage = _Vintage()
190
247
  Tron = _Tron()
191
248
  Document = _Document()
249
+ Stylish = Stylish()
@@ -279,7 +279,7 @@ wheels = [
279
279
 
280
280
  [[package]]
281
281
  name = "emsutil"
282
- version = "0.2.2"
282
+ version = "0.3.0"
283
283
  source = { editable = "." }
284
284
  dependencies = [
285
285
  { name = "loguru" },
@@ -1,58 +0,0 @@
1
- import numpy as np
2
- from .strutil import arry_to_line, matrix_to_lines, arry_to_fwl
3
- from ..emdata import EHFieldFF
4
-
5
- def export_ffdata(filename: str,
6
- thetas: np.ndarray,
7
- phis: np.ndarray,
8
- frequencies: np.ndarray,
9
- fields: list[EHFieldFF],
10
- precision: int = 4) -> None:
11
-
12
- lines = []
13
- lines.append('% Theta (deg)')
14
- lines.append(arry_to_line(thetas, precision=precision))
15
- lines.append('% Phi (deg)')
16
- lines.append(arry_to_line(phis, precision=precision))
17
- lines.append('')
18
- nF = frequencies.shape[0]
19
-
20
- actual_frequencies = []
21
- blocks = []
22
-
23
- T, P = np.meshgrid(thetas, phis, indexing='ij')
24
-
25
- thetal = T.flatten()
26
- phil = P.flatten()
27
-
28
- for iF in range(nF):
29
- freq = frequencies[iF]
30
- actual_frequencies.append(freq)
31
-
32
- farfield = fields[iF]._E
33
- Fx = farfield[0,:,:].squeeze().flatten()
34
- Fy = farfield[1,:,:].squeeze().flatten()
35
- Fz = farfield[2,:,:].squeeze().flatten()
36
-
37
- block_lines = []
38
-
39
- block_lines.append(f'# {freq} (Hz)')
40
- block_lines.append('$ Theta(deg); Phi(deg); E_x[re](V/m); E_x[im](V/m); E_y[re](V/m); E_y[im](V/m); E_z[re](V/m); E_z[im](V/m)')
41
- positions = (0, 14, 24, 38, 52, 66, 80, 94)
42
- for th, ph, ex, ey, ez in zip(thetal, phil, Fx, Fy, Fz):
43
- re_ex = np.real(ex)
44
- im_ex = np.imag(ex)
45
- re_ey = np.real(ey)
46
- im_ey = np.imag(ey)
47
- re_ez = np.real(ez)
48
- im_ez = np.imag(ez)
49
- line_values = np.array([th, ph, re_ex, im_ex, re_ey, im_ey, re_ez, im_ez])
50
- line = arry_to_fwl(line_values, positions, precision=precision)
51
- block_lines.append(line)
52
-
53
- lines.extend(block_lines)
54
- lines.extend('')
55
-
56
- text = '\n'.join(lines)
57
- with open(filename, 'w') as f:
58
- f.write(text)
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