femagtools 1.5.1__py3-none-any.whl → 1.5.2__py3-none-any.whl
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.
- femagtools/__init__.py +1 -1
- femagtools/hxy.py +130 -75
- femagtools/machine/afpm.py +70 -1
- femagtools/machine/sizing.py +3 -1
- femagtools/machine/utils.py +12 -8
- femagtools/plot/nc.py +7 -7
- femagtools/vtu.py +72 -3
- {femagtools-1.5.1.dist-info → femagtools-1.5.2.dist-info}/METADATA +1 -1
- {femagtools-1.5.1.dist-info → femagtools-1.5.2.dist-info}/RECORD +16 -15
- tests/test_hxy.py +19 -0
- tests/test_sizing.py +1 -1
- tests/test_vtu.py +21 -4
- {femagtools-1.5.1.dist-info → femagtools-1.5.2.dist-info}/LICENSE +0 -0
- {femagtools-1.5.1.dist-info → femagtools-1.5.2.dist-info}/WHEEL +0 -0
- {femagtools-1.5.1.dist-info → femagtools-1.5.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.5.1.dist-info → femagtools-1.5.2.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/hxy.py
CHANGED
@@ -4,63 +4,95 @@
|
|
4
4
|
~~~~~~~~~~~~~~
|
5
5
|
|
6
6
|
Reading HXY files (EXPERIMENTAL)
|
7
|
-
|
7
|
+
Build cluster of magnets
|
8
8
|
"""
|
9
9
|
|
10
10
|
import numpy as np
|
11
|
-
|
11
|
+
import logging
|
12
12
|
|
13
13
|
# K-means clustering
|
14
|
+
# https://dev.to/sajal2692/coding-k-means-clustering-using-python-and-numpy-fg1
|
15
|
+
# Sajal Sharma
|
16
|
+
# with adaptions by Ronald Tanner
|
17
|
+
def initialize_random_centroids(K, X):
|
18
|
+
"""Initializes and returns k random centroids"""
|
19
|
+
m, n = np.shape(X)
|
20
|
+
# a centroid should be of shape (1, n), so the centroids array will be of shape (K, n)
|
21
|
+
centroids = np.empty((K, n))
|
22
|
+
for i in range(K):
|
23
|
+
# pick a random data point from X as the centroid
|
24
|
+
centroids[i] = X[np.random.choice(range(m))]
|
25
|
+
return centroids
|
26
|
+
|
27
|
+
|
28
|
+
def initialize_centroids(K, X):
|
29
|
+
"""Initializes and returns k centroids"""
|
30
|
+
c = np.mean(X, axis=0)
|
31
|
+
if K < 2:
|
32
|
+
return [c]
|
33
|
+
alfa = np.arctan2(c[1], c[0]) # angle of center axis
|
34
|
+
T = np.array([[np.cos(alfa), -np.sin(alfa)],
|
35
|
+
[np.sin(alfa), np.cos(alfa)]])
|
36
|
+
p = (np.asarray(X)-c).dot(T) # rotate X
|
37
|
+
d = np.linalg.norm(p, axis=1) # distance to center
|
38
|
+
a = np.arctan2(p[:, 1], p[:, 0]) # angle to center
|
39
|
+
h, b = np.histogram(a, bins=K)
|
40
|
+
return [np.mean(X[(a>r[0]) & (a<r[1])], axis=0)
|
41
|
+
for r in np.array((b[:-1], b[1:])).T]
|
42
|
+
|
43
|
+
|
44
|
+
def closest_centroid(x, centroids, K):
|
45
|
+
"""Finds and returns the index of the closest centroid for a given vector x"""
|
46
|
+
distances = np.empty(K)
|
47
|
+
for i in range(K):
|
48
|
+
distances[i] = np.linalg.norm(centroids[i] - x)
|
49
|
+
return np.argmin(distances) # return the index of the lowest distance
|
50
|
+
|
51
|
+
|
52
|
+
def create_clusters(centroids, K, X):
|
53
|
+
"""Returns an array of cluster indices for all the data samples"""
|
54
|
+
m, _ = np.shape(X)
|
55
|
+
cluster_idx = np.empty(m, dtype=int)
|
56
|
+
for i in range(m):
|
57
|
+
cluster_idx[i] = closest_centroid(X[i], centroids, K)
|
58
|
+
return cluster_idx
|
59
|
+
|
60
|
+
|
61
|
+
def compute_means(cluster_idx, K, X):
|
62
|
+
"""Computes and returns the new centroids of the clusters"""
|
63
|
+
_, n = np.shape(X)
|
64
|
+
centroids = np.empty((K, n))
|
65
|
+
for i in range(K):
|
66
|
+
points = X[cluster_idx == i] # gather points for the cluster i
|
67
|
+
centroids[i] = np.mean(points, axis=0) # use axis=0 to compute means across points
|
68
|
+
return centroids
|
69
|
+
|
70
|
+
|
71
|
+
def run_Kmeans(K, X, max_iterations=500):
|
72
|
+
"""Runs the K-means algorithm and computes the final clusters"""
|
73
|
+
# initialize centroids
|
74
|
+
centroids = initialize_centroids(K, X)
|
75
|
+
# loop till max_iterations or convergance
|
76
|
+
logging.debug(f"initial centroids: {centroids}")
|
77
|
+
for _ in range(max_iterations):
|
78
|
+
# create clusters by assigning the samples to the closet centroids
|
79
|
+
clusters = create_clusters(centroids, K, X)
|
80
|
+
previous_centroids = centroids
|
81
|
+
# compute means of the clusters and assign to centroids
|
82
|
+
centroids = compute_means(clusters, K, X)
|
83
|
+
# if the new_centroids are the same as the old centroids, return clusters
|
84
|
+
diff = previous_centroids - centroids
|
85
|
+
if not diff.any():
|
86
|
+
return clusters
|
87
|
+
return clusters
|
88
|
+
|
89
|
+
"""references properties i to magnet k"""
|
14
90
|
class point():
|
15
91
|
def __init__(self, index, k, coord):
|
16
92
|
self.index = index
|
17
93
|
self.coord = coord
|
18
94
|
self.k = k
|
19
95
|
|
20
|
-
def make_k_mapping(points):
|
21
|
-
region = defaultdict(list)
|
22
|
-
for p in points:
|
23
|
-
region[p.k] = region[p.k] + [p.coord]
|
24
|
-
return region
|
25
|
-
|
26
|
-
def calc_k_means(region):
|
27
|
-
return [np.mean(region[k], axis=0) for k in region]
|
28
|
-
|
29
|
-
def update_k(points, means):
|
30
|
-
for p in points:
|
31
|
-
dists = [np.linalg.norm(m - p.coord) for m in means]
|
32
|
-
p.k = np.argmin(dists)
|
33
|
-
|
34
|
-
def fit(points, epochs=10):
|
35
|
-
for e in range(epochs):
|
36
|
-
region = make_k_mapping(points)
|
37
|
-
means = calc_k_means(region)
|
38
|
-
update_k(points, means)
|
39
|
-
return means, points
|
40
|
-
|
41
|
-
def evaluate(points):
|
42
|
-
region = make_k_mapping(points)
|
43
|
-
means = calc_k_means(region)
|
44
|
-
dists = [np.linalg.norm(means[p.k]-p.coord) for p in points]
|
45
|
-
return np.mean(dists)
|
46
|
-
|
47
|
-
def llf_(y, X, pr):
|
48
|
-
# return maximized log likelihood
|
49
|
-
nobs = float(X.shape[0])
|
50
|
-
nobs2 = nobs / 2.0
|
51
|
-
nobs = float(nobs)
|
52
|
-
resid = y - pr
|
53
|
-
ssr = np.sum((resid)**2)
|
54
|
-
llf = -nobs2*np.log(2*np.pi) - nobs2*np.log(ssr / nobs) - nobs2
|
55
|
-
return llf
|
56
|
-
|
57
|
-
|
58
|
-
def aic(y, X, pr, p):
|
59
|
-
# return aic metric
|
60
|
-
llf = llf_(y, X, pr)
|
61
|
-
return -2*llf+2*p
|
62
|
-
|
63
|
-
|
64
96
|
def readSections(f):
|
65
97
|
section = []
|
66
98
|
movepos = False
|
@@ -83,44 +115,67 @@ def readSections(f):
|
|
83
115
|
|
84
116
|
|
85
117
|
def read(filename, num_magnets):
|
86
|
-
"""read hxy file and return values grouped to magnets
|
118
|
+
"""read hxy file and return values grouped to magnets
|
119
|
+
returns:
|
120
|
+
list of m=num_magnets dicts
|
121
|
+
pos: list of n positions in degree
|
122
|
+
e: n lists of center coordinates of elements in m
|
123
|
+
hxy: n lists of field strengths in kA/m
|
124
|
+
bxy: n lists of flux densities in T
|
125
|
+
mxy: n lists of magnetization in T
|
126
|
+
havg: average of field strengths kA/m
|
127
|
+
hmax: maximum of field strengths kA/m
|
128
|
+
"""
|
87
129
|
hxy = []
|
88
130
|
with open(filename, encoding='latin1', errors='ignore') as f:
|
131
|
+
n = 0
|
132
|
+
k = 0
|
89
133
|
for s in readSections(f):
|
90
134
|
pos = float(s[0].split()[-1])
|
91
135
|
num = np.array([[float(x) for x in l.split()] for l in s[5:] if l])
|
92
136
|
hxy.append({'pos': pos, 'e': num[:, :2], 'hxy': num[:, 2:4],
|
93
137
|
'bxy': num[:, 4:6], 'mxy':num[:, 6:]})
|
138
|
+
logging.info("HXY Section %d: pos %f shape %s", n, pos, num.shape)
|
139
|
+
n += 1
|
140
|
+
if k == 0:
|
141
|
+
k = num.shape[1]
|
94
142
|
K = num_magnets
|
95
|
-
|
96
|
-
|
97
|
-
|
143
|
+
y_preds = run_Kmeans(num_magnets, np.array(hxy[0]['e']))
|
144
|
+
logging.info("Kmeans: %s",
|
145
|
+
[y_preds[y_preds==k].shape[0] for k in range(K)])
|
146
|
+
points = [point(i, k, hxy[0]['e'][i]) for i, k in enumerate(y_preds)]
|
98
147
|
# move values to magnets:
|
99
|
-
magnets = [{'e': [p.
|
100
|
-
|
148
|
+
magnets = [{'e': [[h['e'][p.index]*1e-3
|
149
|
+
for p in points if p.k == k]
|
150
|
+
for h in hxy]}
|
101
151
|
for k in range(K)]
|
102
|
-
|
103
|
-
for
|
104
|
-
for
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
for
|
112
|
-
for k in hkeys:
|
113
|
-
magk[k].append(mk[k])
|
114
|
-
for mag in magnets:
|
115
|
-
for k in ['e'] + hkeys:
|
116
|
-
mag[k] = np.array(mag[k])
|
117
|
-
mag['havg'] = []
|
118
|
-
mag['hmax'] = []
|
119
|
-
for hpos in mag['hxy']:
|
120
|
-
h = np.abs(np.linalg.norm(hpos, axis=1))
|
121
|
-
mag['havg'].append(np.mean(h))
|
122
|
-
mag['hmax'].append(np.max(h))
|
123
|
-
|
124
|
-
# Note dimension of hkeys is (positions x elements x 2)
|
152
|
+
|
153
|
+
for k, mag in enumerate(magnets):
|
154
|
+
mag['pos'] = [h['pos'] for h in hxy]
|
155
|
+
for mk in ['hxy', 'bxy', 'mxy']:
|
156
|
+
mag[mk] = [[h[mk][p.index] for p in points if p.k == k]
|
157
|
+
for h in hxy]
|
158
|
+
hxyabs = [np.linalg.norm(hxy, axis=1)
|
159
|
+
for hxy in mag['hxy']]
|
160
|
+
mag['havg'] = [np.mean(a) for a in hxyabs]
|
161
|
+
mag['hmax'] = [np.max(a) for a in hxyabs]
|
125
162
|
|
126
163
|
return magnets
|
164
|
+
|
165
|
+
if __name__ == '__main__':
|
166
|
+
import sys
|
167
|
+
import matplotlib.pyplot as plt
|
168
|
+
logging.basicConfig(level=logging.INFO,
|
169
|
+
format='%(asctime)s %(message)s')
|
170
|
+
magnets = read(sys.argv[1], int(sys.argv[2]))
|
171
|
+
for m in magnets:
|
172
|
+
print(f"{len(m['e'][0])}: Havg {m['havg']} Hmax {m['hmax']}")
|
173
|
+
|
174
|
+
fig, ax = plt.subplots()
|
175
|
+
for m in magnets:
|
176
|
+
b = np.array(m['e'][0])
|
177
|
+
ax.scatter(*b.T)
|
178
|
+
ax.set_aspect('equal')
|
179
|
+
ax.autoscale(enable=True)
|
180
|
+
ax.axis('off')
|
181
|
+
plt.show()
|
femagtools/machine/afpm.py
CHANGED
@@ -11,8 +11,9 @@ from .. import model
|
|
11
11
|
from .. import utils
|
12
12
|
from .. import windings
|
13
13
|
from .. import femag
|
14
|
-
from scipy.interpolate import RegularGridInterpolator, interp1d
|
14
|
+
from scipy.interpolate import RegularGridInterpolator, interp1d, RectBivariateSpline
|
15
15
|
from scipy.integrate import quad
|
16
|
+
import copy
|
16
17
|
|
17
18
|
logger = logging.getLogger(__name__)
|
18
19
|
|
@@ -38,6 +39,50 @@ def _integrate1d(radius, val):
|
|
38
39
|
return interp((x))
|
39
40
|
return quad(func, radius[0], radius[-1])[0]
|
40
41
|
|
42
|
+
def ld_interpol(i1, beta, v):
|
43
|
+
'''interpolate Ld at beta angle 0°, -180°'''
|
44
|
+
# ld
|
45
|
+
cur = copy.deepcopy(i1)
|
46
|
+
betad = copy.deepcopy(beta)
|
47
|
+
if np.amin(beta) < -90 and \
|
48
|
+
np.amax(beta) > -90:
|
49
|
+
# motor and generator
|
50
|
+
v[0] = v[1]
|
51
|
+
v[-1] = v[-2]
|
52
|
+
|
53
|
+
dbeta = np.abs(beta[0][0] - beta[1][0])
|
54
|
+
bp = [[beta[0][0]-dbeta for i in range(len(np.unique(i1)))]] + beta[1:-1] + \
|
55
|
+
[[dbeta for i in range(len(np.unique(i1)))]]
|
56
|
+
else:
|
57
|
+
v[-1] = v[-2]
|
58
|
+
dbeta = np.abs(beta[0][0] - beta[1][0])
|
59
|
+
bp = beta[0:-1] + \
|
60
|
+
[[dbeta for i in range(len(np.unique(i1)))]]
|
61
|
+
|
62
|
+
return RectBivariateSpline(np.unique(bp), np.unique(cur), \
|
63
|
+
np.array(v)).ev(*[betad, i1]).tolist()
|
64
|
+
|
65
|
+
def lq_interpol(i1, beta, v):
|
66
|
+
'''interpolate Lq at beta -90°'''
|
67
|
+
if -90 not in np.unique(beta):
|
68
|
+
return v
|
69
|
+
# lq
|
70
|
+
betad = copy.deepcopy(beta)
|
71
|
+
if np.amin(beta) < -90 and \
|
72
|
+
np.amax(beta) > -90:
|
73
|
+
# motor and generator
|
74
|
+
inx = np.argwhere(np.array(beta) == -90).squeeze()
|
75
|
+
v.pop(inx[0, 0])
|
76
|
+
bp = beta[0:inx[0, 0]] + beta[inx[0, 0]+1:]
|
77
|
+
cp = i1[0:inx[0, 0]] + i1[inx[0, 0]+1:]
|
78
|
+
else:
|
79
|
+
v[0] = v[1]
|
80
|
+
dbeta = np.abs(beta[0][0] - beta[1][0])
|
81
|
+
bp = [[-90-dbeta for i in i1[0]]] + beta[1::]
|
82
|
+
cp = i1
|
83
|
+
cur = copy.deepcopy(cp)
|
84
|
+
return RectBivariateSpline(np.unique(bp), np.unique(cur), \
|
85
|
+
np.array(v)).ev(*[betad, i1]).tolist()
|
41
86
|
|
42
87
|
def parident(workdir, engine, temp, machine,
|
43
88
|
magnetizingCurves, magnetMat=[], condMat=[],
|
@@ -243,6 +288,29 @@ def parident(workdir, engine, temp, machine,
|
|
243
288
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
244
289
|
psiq = np.reshape([r['psiq'] for r in postp],
|
245
290
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
291
|
+
|
292
|
+
ld = np.reshape([r['Ld'] for r in postp],
|
293
|
+
(-1, num_beta_steps)).T.tolist()
|
294
|
+
lq = np.reshape([r['Lq'] for r in postp],
|
295
|
+
(-1, num_beta_steps)).T.tolist()
|
296
|
+
# interpolation ld, lq
|
297
|
+
curr, angl = [], []
|
298
|
+
for cr in range(len(beta)):
|
299
|
+
curr.append(i1)
|
300
|
+
for al in beta:
|
301
|
+
tmp = []
|
302
|
+
for cr in range(len(i1)):
|
303
|
+
tmp.append(al)
|
304
|
+
angl.append(tmp)
|
305
|
+
try:
|
306
|
+
xx, yy = copy.deepcopy(curr), copy.deepcopy(angl)
|
307
|
+
ld = ld_interpol(xx, yy, ld)
|
308
|
+
xx, yy = copy.deepcopy(curr), copy.deepcopy(angl)
|
309
|
+
lq = lq_interpol(xx, yy, lq)
|
310
|
+
except:
|
311
|
+
ld = np.zeros_like(psid).tolist()
|
312
|
+
lq = np.zeros_like(psid).tolist()
|
313
|
+
|
246
314
|
torque = np.reshape([r['torque'] for r in postp],
|
247
315
|
(-1, num_beta_steps)).T
|
248
316
|
losses = {k: np.flip(np.reshape([r['plfe'][k] for r in postp],
|
@@ -259,6 +327,7 @@ def parident(workdir, engine, temp, machine,
|
|
259
327
|
ldq.append({'temperature': magtemp,
|
260
328
|
'i1':i1, 'beta':beta,
|
261
329
|
'psid': psid.tolist(), 'psiq': psiq.tolist(),
|
330
|
+
'ld': ld, 'lq': lq,
|
262
331
|
'torque': torque.tolist(),
|
263
332
|
'losses': losses})
|
264
333
|
# T = 3/2 p (Psid iq - Psiq id)
|
femagtools/machine/sizing.py
CHANGED
@@ -736,8 +736,10 @@ def im(pnom: float, speed: float, p: int, **kwargs) -> dict:
|
|
736
736
|
slots = []
|
737
737
|
r = get_stator_dimensions(par, slots=slots)
|
738
738
|
# rotor parameters
|
739
|
+
rtype = kwargs.get('rtype', 'rotorKs2')
|
739
740
|
r['rotor'] = get_im_rotor_dimensions(
|
740
|
-
par['cos_phi']*r['A'], r['Da2'], r['psi1'], r['lfe'],
|
741
|
+
par['cos_phi']*r['A'], r['Da2'], r['psi1'], r['lfe'],
|
742
|
+
par, rtype=rtype)
|
741
743
|
_set_genpars(r, 2*par['p'])
|
742
744
|
r['name'] = f"IM-{r['poles']}"
|
743
745
|
return r
|
femagtools/machine/utils.py
CHANGED
@@ -350,21 +350,27 @@ def dqparident(workdir, engine, temp, machine,
|
|
350
350
|
"""
|
351
351
|
import pathlib
|
352
352
|
|
353
|
-
|
353
|
+
wdgk = 'windings' if 'windings' in machine else 'winding'
|
354
|
+
da1 = machine['bore_diam']
|
354
355
|
Q1 = machine['stator']['num_slots']
|
356
|
+
lfe = machine['lfe']
|
357
|
+
g = machine[wdgk].get('num_par_wdgs', 1)
|
355
358
|
slotmodel = [k for k in machine['stator'] if isinstance(
|
356
359
|
machine['stator'][k], dict)][-1]
|
357
360
|
if slotmodel == 'stator1':
|
358
361
|
hs = machine['stator']['stator1']['slot_rf1'] - \
|
359
362
|
machine['stator']['stator1']['tip_rh1']
|
360
363
|
else:
|
361
|
-
|
362
|
-
|
364
|
+
dy1 = machine['outer_diam']
|
365
|
+
hs = machine['stator'][slotmodel].get(
|
366
|
+
'slot_height', 0.6*(dy1-da1)/2)
|
367
|
+
|
363
368
|
N = machine[wdgk]['num_wires']
|
364
|
-
Jmax =
|
369
|
+
Jmax = 20e6 # max current density in A/m2
|
370
|
+
f = machine[wdgk].get('fillfac', 0.42)
|
371
|
+
Acu = f*0.5*np.pi*(da1+hs)*hs
|
372
|
+
i1_max = round(Acu/Q1/N*Jmax/10)*10
|
365
373
|
|
366
|
-
i1_max = round(0.28*np.pi*hs*(da1+hs)/Q1/N*Jmax*1e5)*10 * \
|
367
|
-
machine[wdgk].get('num_par_wdgs', 1)
|
368
374
|
period_frac = kwargs.get('period_frac', 6)
|
369
375
|
if machine.get('external_rotor', False):
|
370
376
|
period_frac = 1 # TODO: missing femag support
|
@@ -381,8 +387,6 @@ def dqparident(workdir, engine, temp, machine,
|
|
381
387
|
|
382
388
|
wdg = windings.Winding(wpar)
|
383
389
|
|
384
|
-
lfe = machine['lfe']
|
385
|
-
g = machine[wdgk].get('num_par_wdgs', 1)
|
386
390
|
if 'wire_gauge' in machine[wdgk]:
|
387
391
|
aw = machine[wdgk]['wire_gauge']
|
388
392
|
elif 'dia_wire' in machine[wdgk]:
|
femagtools/plot/nc.py
CHANGED
@@ -84,17 +84,16 @@ def _contour(ax, title, elements, values, label='',
|
|
84
84
|
for n in nc.nodes],
|
85
85
|
color='gray', alpha=0.1, lw=0))
|
86
86
|
valid_values = np.logical_not(np.isnan(values))
|
87
|
-
|
88
|
-
|
87
|
+
vertices = [[v.xy for v in e.vertices] for e in elements]
|
88
|
+
patches = np.array([Polygon(xy) for xy in vertices])[valid_values]
|
89
89
|
p = PatchCollection(patches, match_original=False,
|
90
90
|
cmap=cmap, alpha=alpha)
|
91
91
|
p.set_array(np.asarray(values)[valid_values])
|
92
92
|
ax.add_collection(p)
|
93
93
|
cb = plt.colorbar(p, shrink=0.9)
|
94
94
|
|
95
|
-
for patch in np.array([Polygon(
|
96
|
-
|
97
|
-
for e in elements])[np.isnan(values)]:
|
95
|
+
for patch in np.array([Polygon(xy, fc='white', alpha=1.0)
|
96
|
+
for xy in vertices])[np.isnan(values)]:
|
98
97
|
ax.add_patch(patch)
|
99
98
|
if label:
|
100
99
|
cb.set_label(label=label)
|
@@ -135,9 +134,10 @@ def demag_pos(isa, pos=-1, icur=-1, ibeta=-1, cmap=DEFAULT_CMAP, ax=0):
|
|
135
134
|
x = isa.pos_el_fe_induction[i]
|
136
135
|
|
137
136
|
hpol = demag[:, i]
|
137
|
+
hmax = np.max(hpol)
|
138
138
|
hpol[hpol == 0] = np.nan
|
139
|
-
_contour(ax, f'Demagnetization at pos. {round(x/np.pi*180):.1f}°,'
|
140
|
-
f'{isa.MAGN_TEMPERATURE} °C (max -{
|
139
|
+
_contour(ax, f'Demagnetization at pos. {round(x/np.pi*180):.1f}°, '
|
140
|
+
f'{isa.MAGN_TEMPERATURE} °C (max -{hmax:.1f} kA/m)',
|
141
141
|
emag, hpol, '-H / kA/m', cmap, isa)
|
142
142
|
logger.info("Max demagnetization %f kA/m", np.nanmax(hpol))
|
143
143
|
|
femagtools/vtu.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
"""Read FEMAG vtu files
|
2
2
|
|
3
3
|
"""
|
4
|
-
import
|
4
|
+
import logging
|
5
5
|
import pathlib
|
6
6
|
import numpy as np
|
7
|
+
import vtk
|
8
|
+
from vtkmodules.util.numpy_support import vtk_to_numpy
|
7
9
|
|
8
10
|
|
9
11
|
class Reader(object):
|
@@ -23,11 +25,13 @@ class Reader(object):
|
|
23
25
|
self.field_data_names = []
|
24
26
|
self.point_data_names = []
|
25
27
|
self.cell_data_names = []
|
28
|
+
assert pathlib.Path(pathname).exists(), f"{pathname} not found"
|
26
29
|
if pathlib.Path(pathname).suffix == '.vtu':
|
27
30
|
self.filenames = [pathlib.Path(pathname)]
|
28
31
|
else:
|
29
32
|
self.filenames = sorted(pathlib.Path(pathname).glob(
|
30
33
|
"*.vtu"))
|
34
|
+
|
31
35
|
self.reader.SetFileName(str(self.filenames[0]))
|
32
36
|
self.reader.Update()
|
33
37
|
self.field_data_names = [
|
@@ -181,7 +185,7 @@ class Reader(object):
|
|
181
185
|
point_vec.append(self.data[pnt_data][i].GetValue(pnt-1))
|
182
186
|
return point_vec
|
183
187
|
|
184
|
-
def get_cell_vector(self, cell_data, cell) -> list:
|
188
|
+
def get_cell_vector(self, cell_data, cell=0) -> list:
|
185
189
|
'''Read cell data
|
186
190
|
|
187
191
|
Args:
|
@@ -195,6 +199,9 @@ class Reader(object):
|
|
195
199
|
if cell_data not in self.data:
|
196
200
|
self.read_data([cell_data])
|
197
201
|
|
202
|
+
if cell<=0:
|
203
|
+
return vtk_to_numpy(
|
204
|
+
self.output.GetCellData().GetAbstractArray(cell_data))
|
198
205
|
i = self.cell_data_names.index(cell_data)
|
199
206
|
noc = self.output.GetCellData().GetAbstractArray(i).GetNumberOfComponents()
|
200
207
|
if noc == 1:
|
@@ -228,12 +235,64 @@ class Reader(object):
|
|
228
235
|
else:
|
229
236
|
return [cell_vec_x, cell_vec_y, cell_vec_z]
|
230
237
|
|
238
|
+
def hrphi(self, scf, elements, magtemp):
|
239
|
+
"""return H values for each element in polar coord system
|
240
|
+
(experimental)
|
241
|
+
Args:
|
242
|
+
elements: list of model elements
|
243
|
+
magtemp: magnet temperature in degree Celsius
|
244
|
+
scf: scale factor (poles/poles in model)
|
245
|
+
"""
|
246
|
+
MUE0 = 4e-7*np.pi
|
247
|
+
b = vtk_to_numpy(
|
248
|
+
self.output.GetCellData().GetAbstractArray("b"))[:, :2]
|
249
|
+
e = elements[0]
|
250
|
+
x, y = np.mean(vtk_to_numpy(
|
251
|
+
self.output.GetCell(e.key-1).GetPoints().GetData()), axis=0)[:2]
|
252
|
+
rotpos = np.arctan2(y, x) - np.arctan2(e.center[1], e.center[0])
|
253
|
+
psign = 1 if rotpos / scf > 1 else -1
|
254
|
+
|
255
|
+
h = np.empty((len(elements), 2))
|
256
|
+
for i, e in enumerate(elements):
|
257
|
+
x, y = e.center
|
258
|
+
alfa = np.arctan2(y, x)
|
259
|
+
b1, b2 = b[e.key-1]
|
260
|
+
btempc = 1. + e.br_temp_coef*(magtemp - 20.)
|
261
|
+
m1 = e.mag[0]*np.cos(alfa) + e.mag[1]*np.sin(alfa)
|
262
|
+
m2 = -e.mag[0]*np.sin(alfa) + e.mag[1]*np.cos(alfa)
|
263
|
+
h[i] = abs(e.reluc[0])/MUE0*np.array((
|
264
|
+
(b1 - psign*btempc*m1), (b2 - psign*btempc*m2)))
|
265
|
+
logging.debug("H shape %s", h.shape)
|
266
|
+
return h
|
267
|
+
|
268
|
+
|
269
|
+
def demag(self, elements):
|
270
|
+
"""return demag values for each element in kA/m
|
271
|
+
Args:
|
272
|
+
elements: list of model elements
|
273
|
+
Returns:
|
274
|
+
list of demags from each vtu file in set
|
275
|
+
"""
|
276
|
+
dlist = []
|
277
|
+
for filename in self.filenames:
|
278
|
+
self.reader.SetFileName(str(filename))
|
279
|
+
self.reader.Update()
|
280
|
+
d = vtk_to_numpy(
|
281
|
+
self.output.GetCellData().GetAbstractArray("demagnetization"))
|
282
|
+
dm = np.empty((len(elements)))
|
283
|
+
for i, e in enumerate(elements):
|
284
|
+
dm[i] = d[e.key-1]
|
285
|
+
dlist.append(dm)
|
286
|
+
logging.debug("Demag shape %s", np.array(dlist).shape)
|
287
|
+
return dlist
|
288
|
+
|
289
|
+
|
231
290
|
def get_data_vector(self, data_name, key=0) -> list:
|
232
291
|
'''Read data of fiels, point or cell
|
233
292
|
|
234
293
|
Args:
|
235
294
|
data_name : str Name of data to read
|
236
|
-
|
295
|
+
key : int (optional) Key of point or cell
|
237
296
|
|
238
297
|
Returns:
|
239
298
|
List of values within the time window
|
@@ -246,6 +305,16 @@ class Reader(object):
|
|
246
305
|
return self.get_cell_vector(data_name, key)
|
247
306
|
return []
|
248
307
|
|
308
|
+
def __repr__(self):
|
309
|
+
fmt = [f"N Cells {self.output.GetNumberOfCells()} N Points {self.output.GetNumberOfPoints()}"]
|
310
|
+
fmt += [
|
311
|
+
f"{self.output.GetPointData().GetAbstractArray(i).GetName()} Points"
|
312
|
+
for i in range(self.output.GetPointData().GetNumberOfArrays())]
|
313
|
+
fmt += [
|
314
|
+
f"{self.output.GetCellData().GetAbstractArray(i).GetName()} Cells"
|
315
|
+
for i in range(self.output.GetCellData().GetNumberOfArrays())]
|
316
|
+
return '\n'.join(fmt)
|
317
|
+
|
249
318
|
|
250
319
|
def read(filename) -> Reader:
|
251
320
|
"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: femagtools
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.2
|
4
4
|
Summary: Python API for FEMAG
|
5
5
|
Author-email: Ronald Tanner <tar@semafor.ch>, Dapu Zhang <dzhang@gtisoft.com>, Beat Holm <hob@semafor.ch>, Günther Amsler <amg@semafor.ch>, Nicolas Mauchle <mau@semafor.ch>
|
6
6
|
License: Copyright (c) 2016-2023, Semafor Informatik & Energie AG, Basel
|
@@ -1,4 +1,4 @@
|
|
1
|
-
femagtools/__init__.py,sha256=
|
1
|
+
femagtools/__init__.py,sha256=kGZSfjN0Y6_CwYhVU9ki2misQXnylS2nmIQNI60q1lk,1615
|
2
2
|
femagtools/airgap.py,sha256=s8NoKFvBhkINxkMLG02RbLZA9PiSx9KMtPjByy1WwNc,1584
|
3
3
|
femagtools/amazon.py,sha256=O1ICuv21XDAJi1qK1Sigs2TdS6hDZP19OzvmE2t76wU,12069
|
4
4
|
femagtools/amela.py,sha256=pHjfXzpANI-7oz8MtrqNcyDZ6PxVM91vCJuvYhHy1rk,13891
|
@@ -22,7 +22,7 @@ femagtools/getset.py,sha256=yJ6Em35DeWK7WNZW0qjjS5s7LUkVh5mbgxF59HHm5FM,3017
|
|
22
22
|
femagtools/gmsh.py,sha256=IKhNiviIBji4cMxAhxaYXNqBRMNAPSKsBGdnGyxkyQw,3903
|
23
23
|
femagtools/google.py,sha256=ugRyHY1zBjHR4aNfbA7GeF-ZU_NgleuVTZaWpi_XLT4,17144
|
24
24
|
femagtools/grid.py,sha256=s7LfKKLm2H4-cza2kSEANq6vwxq10Su3TJl3kHShHRA,1561
|
25
|
-
femagtools/hxy.py,sha256=
|
25
|
+
femagtools/hxy.py,sha256=PkiZ_-CRhtvtpkmLAP8iMtwvzh7CjKGGcAbOhFb4Nls,6275
|
26
26
|
femagtools/isa7.py,sha256=KDZcakwRdlC8KECpQKoFzI-L2ZILJSaUp_MNOZNOfoE,57374
|
27
27
|
femagtools/jhb.py,sha256=stJxkmzHpfUIBVcFw7jWbV5KN9_EFqzOCgacyhUqWvM,1779
|
28
28
|
femagtools/job.py,sha256=dOatzr10nIda76CjVRSS0SfEWC8_BAw0kowli523qbY,11320
|
@@ -44,7 +44,7 @@ femagtools/tks.py,sha256=FuEKiWcSnOW2Hp2NxCq1hBeQdRFkHutaJuctrhxh8Ws,6228
|
|
44
44
|
femagtools/ts.py,sha256=JZbiXhss6f5J8gDhOMmfZe-fkroBA1BRcpGE5PGZjWU,47175
|
45
45
|
femagtools/utils.py,sha256=Pi-FeM81Fm0m3GF1Mq9EYcTNeW_BI6qIXVGhbYcC1cY,1434
|
46
46
|
femagtools/vbf.py,sha256=9XGfhftmD9carU8ByQ5DwqoR4daq5mJ39eMqruwml0Q,2444
|
47
|
-
femagtools/vtu.py,sha256=
|
47
|
+
femagtools/vtu.py,sha256=Sf83dHIfCKY2km-MIUHKKoj-JKN4PDX7kkPLZXyIYY4,10723
|
48
48
|
femagtools/windings.py,sha256=6ioABZRWQ3xA4kmEz2NUkXh-C-FmW9YYkjQKs5YakQs,22197
|
49
49
|
femagtools/dxfsl/__init__.py,sha256=MywcCdpKPKs4qJBJJgeDsikJFJ2P48dbTuNk303f5pM,76
|
50
50
|
femagtools/dxfsl/area.py,sha256=3YSa6tNW1vToZiUuo-0cghxtYG0jzIOU91dEibueltE,55787
|
@@ -59,13 +59,13 @@ femagtools/dxfsl/machine.py,sha256=E2w1vduaRn1yWfp6cQtvN4Rf0AeJWqbHNtOF5YofeEI,3
|
|
59
59
|
femagtools/dxfsl/plotrenderer.py,sha256=lJFEH0Jdsph3atcABMS6IweKNPANxJA1aF0YlMdk_p0,12725
|
60
60
|
femagtools/dxfsl/shape.py,sha256=BYIePcfpSPLgE5DjwTs5ofQbuIF4MdTvCitwrvNQiw4,46010
|
61
61
|
femagtools/machine/__init__.py,sha256=m3DnYBP8Wxh-qDoFhkPVlXUGcA4fjDOVleqo3YQ4syA,7728
|
62
|
-
femagtools/machine/afpm.py,sha256=
|
62
|
+
femagtools/machine/afpm.py,sha256=TRRGKZWpbXWPXMJQPXAjfOtmXm1XPCnwgzhgBjexfl8,24813
|
63
63
|
femagtools/machine/effloss.py,sha256=aaSmmxKd_KWMasHUHipYDcZOw-fvTHNa38MWFnpVock,13130
|
64
64
|
femagtools/machine/im.py,sha256=ScIOLrlc4CPLYFNx2MmJqkpmbky_HXxFGZbMWUNGBrk,37881
|
65
65
|
femagtools/machine/pm.py,sha256=suVFbQ8E8winWaoSQOYnA3Qggn_8ObQVS7mjigwO3Ig,53319
|
66
|
-
femagtools/machine/sizing.py,sha256=
|
66
|
+
femagtools/machine/sizing.py,sha256=aN_OahewjTTBHnpRNfLh1AGFhqnoeZVuMBeb_3MCIVI,23096
|
67
67
|
femagtools/machine/sm.py,sha256=iiFBLmMliDvx3rdKscU7XZLu0TK66F__BA5S7JlbR-8,32958
|
68
|
-
femagtools/machine/utils.py,sha256=
|
68
|
+
femagtools/machine/utils.py,sha256=i2nnwYLTrf_OZbSDgo6uhHpH8-7UaWlRbvgp_BL4JSE,16770
|
69
69
|
femagtools/moo/__init__.py,sha256=zinmWEOrsEz6DmMX0Dbn4t6_1UR-p4bEGqyR1wUQk_Q,175
|
70
70
|
femagtools/moo/algorithm.py,sha256=lNEf0Bur4yFpIJeLtAC3oIus8sOMWTb7jepFlD28YzE,5445
|
71
71
|
femagtools/moo/population.py,sha256=gi8PSVUXkYY5vzgAwWvxfMbH_z51fN58O4-NKoarwzI,10100
|
@@ -79,7 +79,7 @@ femagtools/plot/char.py,sha256=pfmsoSbrE4QuWBaGV9X7s2hT4OSK5ZQ99drmE4y1TDw,11192
|
|
79
79
|
femagtools/plot/fluxdens.py,sha256=NlexRJ3f_8CgKoWrV82ZIsAXPrLhwj98uOe8_fUks7A,1082
|
80
80
|
femagtools/plot/forcedens.py,sha256=37FQLViGsjCh20tSlWlVfLTsvtjzdK_pEQGC2KcQ-xI,2996
|
81
81
|
femagtools/plot/mcv.py,sha256=AKbWhJd20Kcec8Hv9dX32G5yTLPkcWorQS7-3P6m-mQ,2960
|
82
|
-
femagtools/plot/nc.py,sha256=
|
82
|
+
femagtools/plot/nc.py,sha256=CU-6420EYq6S4ZzyqxCOyxrbHIeJ8_aBVxDPM3E2oD4,9516
|
83
83
|
femagtools/plot/phasor.py,sha256=5iqxCQi_idkdqYALJjQb6YFr_Zv5xsUayDoKL5HzsdE,4765
|
84
84
|
femagtools/plot/wdg.py,sha256=UooR1K8JDoVjKWEox_AfkBY40L87jk2L9OdIFz4O-OY,8462
|
85
85
|
femagtools/templates/FE-losses.mako,sha256=Rql5_8Q6_uthpr-uFXMUo7tdHehfZYND-7M-ohJXVU8,874
|
@@ -162,6 +162,7 @@ tests/test_erg.py,sha256=kRVzpXa6JDdbxTss18HUWKny9Dx8IMx9uGTrbQCnHwg,523
|
|
162
162
|
tests/test_femag.py,sha256=l7-av3eitLm7bwTuunEmVeTspi82ifPrlz7f1boGdVI,1934
|
163
163
|
tests/test_forcedens.py,sha256=Yzl3SAmJNkZN9dA3aLxRvwY8fKsw077Fl0iJm6zJ5Sk,536
|
164
164
|
tests/test_fsl.py,sha256=I2UqfZgvm5J2kc8sRlDiQY9MH6wIjBmLLx0i-fYqYYA,16623
|
165
|
+
tests/test_hxy.py,sha256=pVb6ZfDhBy5-DXa3gh7RQmLFG8p5cSYB8gdGLC8kjAk,640
|
165
166
|
tests/test_im.py,sha256=55wfCoA8_PuogI_RsC3AjUQCpR84T-HddtHuU1NxfPc,662
|
166
167
|
tests/test_isa7.py,sha256=GJhRj2nncrUpNTIlM4jvG4kKZS7cK19hhQg9KbM3b5Q,3001
|
167
168
|
tests/test_jhb.py,sha256=aDzwr2ZaXlizrPnlLlcI_IT3OpSxuKu-FzBBkIALEDg,824
|
@@ -179,12 +180,12 @@ tests/test_nc.py,sha256=aQNHHDBnyr1mV8yfaBh728tjDkRn3DLUgEaYV5GtBYE,4205
|
|
179
180
|
tests/test_parident.py,sha256=RiEEdRjR6SVebdxPMwkT0FMt7MlHXCfxChHpbAo5reI,1340
|
180
181
|
tests/test_parstudy.py,sha256=wk7WfYQrx5dtv6MnmWCfNAEInvRKsbVXYEUIIR9zLbQ,3200
|
181
182
|
tests/test_pocfile.py,sha256=eiMLBRQxDnHIGiqku6EXcQ3fb7wGIxhXmb20iyLlPRU,5816
|
182
|
-
tests/test_sizing.py,sha256=
|
183
|
+
tests/test_sizing.py,sha256=8tIT8DG1c28aSwkPD4qPryKk3sU2JhXWLYYxhmDQMbM,1131
|
183
184
|
tests/test_sm.py,sha256=FjcAbx4n7kLH00kjnKoGMk6t4_V9TJzIaxM21MkrOjE,83524
|
184
185
|
tests/test_tksreader.py,sha256=8QtPAzxPJbkpxd1Nw2I7ggaTaKaL4WY55JJBHkZAzus,766
|
185
186
|
tests/test_ts.py,sha256=tR2x5cKU9gw2fUprzaPgPbCvmDOHDO36JUPCCoTlY7Y,1833
|
186
187
|
tests/test_vbfreader.py,sha256=-6oAhLJDb7K3Ui5O1mtHvbskawEfgyIH-Of5n-8u-fc,832
|
187
|
-
tests/test_vtu.py,sha256=
|
188
|
+
tests/test_vtu.py,sha256=pGpHuAcaCk5zDYTBBp_akOEenZOpq-IzGl_kaMtodyA,1469
|
188
189
|
tests/test_windings.py,sha256=PerbhIvIeyTuHZbBCORUy9EINKEhVoyN6vshtsrs1xA,4912
|
189
190
|
tests/engines/__init__.py,sha256=l8HD-AY8EwxOoo_VrG3HgEZb2MaHypvnhKCVSkR-DTA,808
|
190
191
|
tests/engines/test_amazon.py,sha256=4uy36NIo0epi3CgjUm8vl4snLpr4NRvUoWi6Zew_zcE,2014
|
@@ -196,9 +197,9 @@ tests/moo/__init__.py,sha256=l8HD-AY8EwxOoo_VrG3HgEZb2MaHypvnhKCVSkR-DTA,808
|
|
196
197
|
tests/moo/test_algorithm.py,sha256=Em8sFm2vzPmuIzRrBBnUQLU_TYuJHSf-kEeozw0XeX4,2563
|
197
198
|
tests/moo/test_population.py,sha256=FvX9LRCxQx0_E2GxHQ5vKwOYFBQiNbT6Lmv5GmNWjTQ,5471
|
198
199
|
tests/moo/test_problem.py,sha256=ALeP4u7g-dFhfwWL8vxivdrrYzVKPjHMCAXzzgyNZbs,467
|
199
|
-
femagtools-1.5.
|
200
|
-
femagtools-1.5.
|
201
|
-
femagtools-1.5.
|
202
|
-
femagtools-1.5.
|
203
|
-
femagtools-1.5.
|
204
|
-
femagtools-1.5.
|
200
|
+
femagtools-1.5.2.dist-info/LICENSE,sha256=V5OED7AzEaOtvbfgNheKOSUeNtijvKQuo84FtSJNkJU,1316
|
201
|
+
femagtools-1.5.2.dist-info/METADATA,sha256=M2C4o3QLWJgrRNDvT0hE7k3yKK1WTroS-lzvUuhdIh0,5685
|
202
|
+
femagtools-1.5.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
203
|
+
femagtools-1.5.2.dist-info/entry_points.txt,sha256=UXpu6KnrykN89sCUaFAIIzn_dYwuxizUS0GcPdoekro,195
|
204
|
+
femagtools-1.5.2.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
|
205
|
+
femagtools-1.5.2.dist-info/RECORD,,
|
tests/test_hxy.py
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
import femagtools.hxy
|
2
|
+
import pathlib
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
|
6
|
+
@pytest.fixture
|
7
|
+
def data_dir():
|
8
|
+
return pathlib.Path(__file__).with_name('data') / 'hxy'
|
9
|
+
|
10
|
+
|
11
|
+
def test_read(data_dir):
|
12
|
+
num_magnets = 2
|
13
|
+
magnets = femagtools.hxy.read(data_dir / 'PM270L8_011.hxy',
|
14
|
+
num_magnets)
|
15
|
+
assert len(magnets) == num_magnets
|
16
|
+
assert set([len(m['e'][0]) for m in magnets]) == {169, 189}
|
17
|
+
assert [m['pos'][0] for m in magnets] == [0.0, 0.0]
|
18
|
+
assert sorted([m['havg'][0] for m in magnets]) == pytest.approx([156.3, 156.5], 0.1)
|
19
|
+
assert sorted([m['hmax'][0] for m in magnets]) == pytest.approx([195.6, 304.4], 0.1)
|
tests/test_sizing.py
CHANGED
tests/test_vtu.py
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
import pytest
|
2
|
+
import pathlib
|
2
3
|
from femagtools import vtu
|
3
4
|
|
4
5
|
|
5
6
|
@pytest.fixture
|
6
|
-
def
|
7
|
-
|
8
|
-
|
7
|
+
def ts_data_dir():
|
8
|
+
return pathlib.Path(__file__).with_name('data') / 'zzz_pm_model_ts_results_1/'
|
9
|
+
|
10
|
+
@pytest.fixture
|
11
|
+
def demag_data_dir():
|
12
|
+
return pathlib.Path(__file__).with_name('data') / 'demag-vtu/'
|
9
13
|
|
10
14
|
|
11
|
-
def test_read(
|
15
|
+
def test_read(ts_data_dir):
|
16
|
+
vtu_data = vtu.read(ts_data_dir / 'zzz_pm_model_ts_0000.vtu')
|
12
17
|
assert vtu_data.field_data_names == [
|
13
18
|
'time [s]', 'angle [rad]',
|
14
19
|
'speed [rad/s]', 'torque [Nm]',
|
@@ -23,3 +28,15 @@ def test_read(vtu_data):
|
|
23
28
|
assert b[0] == pytest.approx([-0.003114], abs=1e-5)
|
24
29
|
assert b[1] == pytest.approx([-0.00313], abs=1e-5)
|
25
30
|
assert b[2] == [0.0]
|
31
|
+
|
32
|
+
def test_demag(demag_data_dir):
|
33
|
+
vtu_data = vtu.read(demag_data_dir / 'PM_130_L10_0000.vtu')
|
34
|
+
keys = [7412, 7413, 7414, 7415, 7416]
|
35
|
+
class Element:
|
36
|
+
def __init__(self, key):
|
37
|
+
self.key = key
|
38
|
+
elements = [Element(k) for k in keys]
|
39
|
+
expected = [241.5, 250.2, 262.3, 276.5, 390.5]
|
40
|
+
actual = vtu_data.demag(elements)
|
41
|
+
assert len(actual) == 1
|
42
|
+
assert actual[0] == pytest.approx(expected, abs=0.1)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|