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.
- {emsutil-0.2.2 → emsutil-0.3.0}/.bumpversion.toml +1 -1
- {emsutil-0.2.2 → emsutil-0.3.0}/PKG-INFO +1 -1
- emsutil-0.3.0/emerge-install-mumps +32 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/pyproject.toml +1 -1
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/emdata.py +15 -12
- emsutil-0.3.0/src/emsutil/inexport/ffdata.py +304 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/themes.py +58 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/uv.lock +1 -1
- emsutil-0.2.2/src/emsutil/inexport/ffdata.py +0 -58
- {emsutil-0.2.2 → emsutil-0.3.0}/.gitignore +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/.python-version +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/README.md +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/__init__.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/const.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/inexport/strutil.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/isola.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/lib.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/material.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/plot/__init__.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/plot/plot2d.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/__init__.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/cmap_maker.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/display.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/display_settings.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/background.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex1.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex2.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex3.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex4.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex5.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/textures/tex6.png +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/pyvista/utils.py +0 -0
- {emsutil-0.2.2 → emsutil-0.3.0}/src/emsutil/rogers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emsutil
|
|
3
|
-
Version: 0.
|
|
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."
|
|
@@ -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.
|
|
26
|
-
thy = np.cos(self.
|
|
27
|
-
thz = -np.sin(self.
|
|
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.
|
|
33
|
-
phy = np.cos(self.
|
|
34
|
-
phz = np.zeros_like(self.
|
|
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()
|
|
@@ -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
|
|
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
|