femagtools 1.5.0__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/amela.py +5 -1
- femagtools/femag.py +23 -5
- femagtools/fsl.py +1 -1
- femagtools/hxy.py +130 -75
- femagtools/isa7.py +3 -1
- femagtools/machine/afpm.py +131 -17
- femagtools/machine/sizing.py +3 -1
- femagtools/machine/utils.py +12 -8
- femagtools/multiproc.py +1 -1
- femagtools/plot/nc.py +15 -10
- femagtools/templates/afm_stator.mako +11 -2
- femagtools/templates/fieldcalc.mako +1 -3
- femagtools/vtu.py +72 -3
- {femagtools-1.5.0.dist-info → femagtools-1.5.2.dist-info}/METADATA +1 -1
- {femagtools-1.5.0.dist-info → femagtools-1.5.2.dist-info}/RECORD +23 -22
- tests/test_hxy.py +19 -0
- tests/test_sizing.py +1 -1
- tests/test_vtu.py +21 -4
- {femagtools-1.5.0.dist-info → femagtools-1.5.2.dist-info}/LICENSE +0 -0
- {femagtools-1.5.0.dist-info → femagtools-1.5.2.dist-info}/WHEEL +0 -0
- {femagtools-1.5.0.dist-info → femagtools-1.5.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.5.0.dist-info → femagtools-1.5.2.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/amela.py
CHANGED
@@ -200,7 +200,11 @@ class Amela():
|
|
200
200
|
for k, i in enumerate(mag_spels):
|
201
201
|
|
202
202
|
cond = i.conduc
|
203
|
-
|
203
|
+
if cond == 0:
|
204
|
+
cond = 625000
|
205
|
+
logger.info('Magnet conductivity equals 0, using 625000 S/m')
|
206
|
+
|
207
|
+
mur = np.abs(1/i.elements[0].reluc[0])
|
204
208
|
logger.debug('Magnet: mur=%s, conductivity=%s', mur, cond)
|
205
209
|
|
206
210
|
pm_elem_key.append([j.key for j in i.elements])
|
femagtools/femag.py
CHANGED
@@ -41,7 +41,7 @@ def handle_process_output(filedes, outfile, log):
|
|
41
41
|
"""read from file descriptor and direct lines to logger and outfile"""
|
42
42
|
with open(outfile, 'w') as fp:
|
43
43
|
for line in filedes:
|
44
|
-
fp.write(
|
44
|
+
fp.write(line.decode())
|
45
45
|
if log:
|
46
46
|
if (b'' == line or
|
47
47
|
b'\x1b' in line or # ignore terminal escape seq
|
@@ -482,7 +482,7 @@ class Femag(BaseFemag):
|
|
482
482
|
basename = pathlib.Path(filename).name
|
483
483
|
outname = os.path.join(self.workdir, basename+'.out')
|
484
484
|
errname = os.path.join(self.workdir, basename+'.err')
|
485
|
-
with open(
|
485
|
+
with open(errname, 'w') as err:
|
486
486
|
logger.info('invoking %s', ' '.join([str(a) for a in args]))
|
487
487
|
proc = subprocess.Popen(
|
488
488
|
args,
|
@@ -495,9 +495,15 @@ class Femag(BaseFemag):
|
|
495
495
|
errs = []
|
496
496
|
# print femag output
|
497
497
|
with io.open(outname, encoding='latin1', errors='ignore') as outfile:
|
498
|
+
errLine = False
|
498
499
|
for l in outfile:
|
499
500
|
if l.find('ERROR') > -1:
|
500
501
|
errs.append(l.strip())
|
502
|
+
errLine = True
|
503
|
+
elif errLine and l.startswith(' '): # additional error line
|
504
|
+
errs.append(l)
|
505
|
+
else:
|
506
|
+
errLine = False
|
501
507
|
|
502
508
|
rc = proc.returncode
|
503
509
|
logger.info("%s exited with returncode %d (num errs=%d)",
|
@@ -508,7 +514,7 @@ class Femag(BaseFemag):
|
|
508
514
|
for l in errfile:
|
509
515
|
errs.append(l.strip())
|
510
516
|
errs.insert(0, 'Exit code {}'.format(rc))
|
511
|
-
raise FemagError(errs)
|
517
|
+
raise FemagError("\n".join(errs))
|
512
518
|
|
513
519
|
def cleanup(self):
|
514
520
|
"removes all created files in workdir"
|
@@ -805,8 +811,8 @@ class ZmqFemag(BaseFemag):
|
|
805
811
|
logger.error("send_fsl: %s", str(e))
|
806
812
|
if timeout: # only first call raises zmq.error.Again
|
807
813
|
return ['{"status":"error", "message":"Femag is not running"}', '{}']
|
808
|
-
msg = str(e)
|
809
|
-
return ['{"status":"error", "message":
|
814
|
+
msg = json.dumps(str(e))
|
815
|
+
return ['{"status":"error", "message":'+msg+'}', '{}']
|
810
816
|
|
811
817
|
def run(self, options=['-b'], restart=False, procId=None,
|
812
818
|
stateofproblem='mag_static'): # noqa: C901
|
@@ -1003,6 +1009,18 @@ class ZmqFemag(BaseFemag):
|
|
1003
1009
|
logger.warning(response[0])
|
1004
1010
|
return [s.decode('latin1') for s in response]
|
1005
1011
|
|
1012
|
+
def exportmesh(self, fslcmds, timeout=120000):
|
1013
|
+
"""get svg format (with mesh) from fsl commands (if any graphic created)
|
1014
|
+
(since FEMAG v2024.1-17) """
|
1015
|
+
response = self.send_request(['SVG+Mesh', fslcmds], timeout=timeout)
|
1016
|
+
try:
|
1017
|
+
rc = json.loads(response[0].decode('latin1'))
|
1018
|
+
if rc['status'] == 'ok':
|
1019
|
+
return self.getfile(rc['result_file'][0])
|
1020
|
+
except json.decoder.JSONDecodeError:
|
1021
|
+
logger.warning(response[0])
|
1022
|
+
return [s.decode('latin1') for s in response]
|
1023
|
+
|
1006
1024
|
def interrupt(self):
|
1007
1025
|
"""send push message to control port to stop current calculation"""
|
1008
1026
|
context = zmq.Context.instance()
|
femagtools/fsl.py
CHANGED
@@ -634,7 +634,7 @@ class Builder:
|
|
634
634
|
def create_analysis(self, sim):
|
635
635
|
pfefunc = sim.get('loss_funct', '')
|
636
636
|
if pfefunc:
|
637
|
-
sim['loss_funct'] =
|
637
|
+
sim['loss_funct'] = 1 # 3?
|
638
638
|
airgap_induc = (self.create_airgap_induc()
|
639
639
|
if sim.get('airgap_induc', 0) else [])
|
640
640
|
felosses = pfefunc.split('\n') + self.create_fe_losses(sim)
|
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/isa7.py
CHANGED
@@ -1357,13 +1357,15 @@ class Element(BaseEntity):
|
|
1357
1357
|
|
1358
1358
|
def demagnetization(self, temperature=20):
|
1359
1359
|
"""return demagnetization Hx, Hy of this element"""
|
1360
|
-
return self.demag_b(self.flux_density(cosys='
|
1360
|
+
return self.demag_b(self.flux_density(cosys='polar'), temperature)
|
1361
1361
|
|
1362
1362
|
def demag_b(self, b, temperature):
|
1363
1363
|
"""return demagnetization Hx, Hy of this element at flux density b
|
1364
1364
|
and temperature"""
|
1365
1365
|
if self.is_magnet():
|
1366
|
+
# assume polar coordinates of b
|
1366
1367
|
pos = np.arctan2(self.center[1], self.center[0])
|
1368
|
+
#pos = 0 # cartesian
|
1367
1369
|
br_temp_corr = 1. + self.br_temp_coef*(temperature - 20.)
|
1368
1370
|
magn = np.sqrt(self.mag[0]**2 + self.mag[1]**2)*br_temp_corr
|
1369
1371
|
alfa = np.arctan2(self.mag[1], self.mag[0]) - pos
|
femagtools/machine/afpm.py
CHANGED
@@ -4,13 +4,16 @@
|
|
4
4
|
import logging
|
5
5
|
import numpy as np
|
6
6
|
from pathlib import Path
|
7
|
+
import shutil
|
7
8
|
from .. import poc
|
8
9
|
from .. import parstudy
|
9
10
|
from .. import model
|
10
11
|
from .. import utils
|
11
12
|
from .. import windings
|
12
|
-
from
|
13
|
+
from .. import femag
|
14
|
+
from scipy.interpolate import RegularGridInterpolator, interp1d, RectBivariateSpline
|
13
15
|
from scipy.integrate import quad
|
16
|
+
import copy
|
14
17
|
|
15
18
|
logger = logging.getLogger(__name__)
|
16
19
|
|
@@ -36,6 +39,50 @@ def _integrate1d(radius, val):
|
|
36
39
|
return interp((x))
|
37
40
|
return quad(func, radius[0], radius[-1])[0]
|
38
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()
|
39
86
|
|
40
87
|
def parident(workdir, engine, temp, machine,
|
41
88
|
magnetizingCurves, magnetMat=[], condMat=[],
|
@@ -124,10 +171,6 @@ def parident(workdir, engine, temp, machine,
|
|
124
171
|
]
|
125
172
|
}
|
126
173
|
|
127
|
-
pstudy = parstudy.List(
|
128
|
-
workdir, condMat=condMat, magnets=magnetMat,
|
129
|
-
magnetizingCurves=magnetizingCurves,
|
130
|
-
cmd=kwargs.get('cmd', None))
|
131
174
|
|
132
175
|
ldq = []
|
133
176
|
for magtemp in temp:
|
@@ -138,12 +181,37 @@ def parident(workdir, engine, temp, machine,
|
|
138
181
|
poc=poc.Poc(999),
|
139
182
|
speed=0)
|
140
183
|
logging.info("Noload simulation")
|
141
|
-
|
142
|
-
|
143
|
-
|
184
|
+
if kwargs.get('use_multiprocessing', True):
|
185
|
+
pstudy = parstudy.List(
|
186
|
+
workdir, condMat=condMat, magnets=magnetMat,
|
187
|
+
magnetizingCurves=magnetizingCurves,
|
188
|
+
cmd=kwargs.get('cmd', None))
|
189
|
+
|
190
|
+
nlresults = pstudy(nlparvardef, machine, nlcalc, engine)
|
191
|
+
if nlresults['status'].count('C') != len(nlresults['status']):
|
192
|
+
raise ValueError('Noload simulation failed %s', nlresults['status'])
|
193
|
+
else:
|
194
|
+
nlresults = {"x": [], "f": []}
|
195
|
+
i = 0
|
196
|
+
for pw, le, sp in zip(pole_width, lfe, linspeed):
|
197
|
+
nlmachine = {k: machine[k] for k in machine}
|
198
|
+
nlmachine['pole_width'] = pw
|
199
|
+
nlmachine['lfe'] = le
|
200
|
+
nlcalc.update({"speed": sp})
|
201
|
+
nlsubdir = f'{workdir}/{i}'
|
202
|
+
nlworkdir = Path(nlsubdir)
|
203
|
+
if nlworkdir.exists():
|
204
|
+
shutil.rmtree(nlworkdir)
|
205
|
+
nlworkdir.mkdir(exist_ok=True)
|
206
|
+
noloadsim = femag.Femag(nlworkdir, condMat=condMat, magnets=magnetMat,
|
207
|
+
magnetizingCurves=magnetizingCurves,
|
208
|
+
cmd=kwargs.get('cmd', None))
|
209
|
+
r = noloadsim(nlmachine, nlcalc)
|
210
|
+
nlresults['f'].append({k: v for k, v in r.items()})
|
211
|
+
i = i + 1
|
144
212
|
nlresults.update(process(lfe, pole_width, machine, nlresults['f']))
|
145
|
-
current_angles = nlresults['f'][0]['current_angles']
|
146
213
|
|
214
|
+
current_angles = nlresults['f'][0]['current_angles']
|
147
215
|
results = []
|
148
216
|
i = 0
|
149
217
|
for l, pw in zip(lfe, pole_width):
|
@@ -152,17 +220,11 @@ def parident(workdir, engine, temp, machine,
|
|
152
220
|
mpart['lfe'] = l
|
153
221
|
subdir = f"{workdir}/{i}"
|
154
222
|
|
155
|
-
gpstudy = parstudy.Grid(
|
156
|
-
subdir, condMat=condMat, magnets=magnetMat,
|
157
|
-
magnetizingCurves=magnetizingCurves,
|
158
|
-
cmd=kwargs.get('cmd', None))
|
159
|
-
|
160
223
|
simulation = dict(
|
161
224
|
calculationMode="torq_calc",
|
162
225
|
wind_temp=20.0,
|
163
226
|
magn_temp=magtemp,
|
164
227
|
angl_i_up=0.0,
|
165
|
-
magnet_loss=True,
|
166
228
|
magn_height=machine['magnet']['afm_rotor']['magn_height'],
|
167
229
|
yoke_height=machine['magnet']['afm_rotor'].get(
|
168
230
|
'yoke_height', 0),
|
@@ -173,8 +235,36 @@ def parident(workdir, engine, temp, machine,
|
|
173
235
|
num_move_steps=60,
|
174
236
|
speed=linspeed[i],
|
175
237
|
num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1))
|
176
|
-
|
177
|
-
|
238
|
+
|
239
|
+
if kwargs.get('use_multiprocessing', True):
|
240
|
+
gpstudy = parstudy.Grid(
|
241
|
+
subdir, condMat=condMat, magnets=magnetMat,
|
242
|
+
magnetizingCurves=magnetizingCurves,
|
243
|
+
cmd=kwargs.get('cmd', None))
|
244
|
+
lresults = gpstudy(parvardef, mpart, simulation, engine)
|
245
|
+
|
246
|
+
else:
|
247
|
+
lresults = {"x": [], "f": []}
|
248
|
+
domain_beta = np.linspace(beta_min, 0, num_beta_steps).tolist()
|
249
|
+
domain_cur = np.linspace(i1_max/num_cur_steps, i1_max, num_cur_steps).tolist()
|
250
|
+
dir_index = 0
|
251
|
+
for cur in domain_cur:
|
252
|
+
for be in domain_beta:
|
253
|
+
simulation['angl_i_up'] = be
|
254
|
+
simulation['current'] = cur
|
255
|
+
lresults['x'].append([be, cur])
|
256
|
+
subsubdir = subdir + f'/{dir_index}'
|
257
|
+
dir_index = dir_index + 1
|
258
|
+
lworkdir = Path(subsubdir)
|
259
|
+
if lworkdir.exists():
|
260
|
+
shutil.rmtree(lworkdir)
|
261
|
+
lworkdir.mkdir(exist_ok=True)
|
262
|
+
loadsim = femag.Femag(lworkdir, condMat=condMat, magnets=magnetMat,
|
263
|
+
magnetizingCurves=magnetizingCurves,
|
264
|
+
cmd=kwargs.get('cmd', None))
|
265
|
+
r = loadsim(mpart, simulation)
|
266
|
+
lresults['f'].append({k: v for k, v in r.items()})
|
267
|
+
|
178
268
|
f = [{k: bch[k]
|
179
269
|
for k in ('linearForce', 'flux', 'losses', 'lossPar')}
|
180
270
|
for bch in lresults['f']]
|
@@ -198,6 +288,29 @@ def parident(workdir, engine, temp, machine,
|
|
198
288
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
199
289
|
psiq = np.reshape([r['psiq'] for r in postp],
|
200
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
|
+
|
201
314
|
torque = np.reshape([r['torque'] for r in postp],
|
202
315
|
(-1, num_beta_steps)).T
|
203
316
|
losses = {k: np.flip(np.reshape([r['plfe'][k] for r in postp],
|
@@ -214,6 +327,7 @@ def parident(workdir, engine, temp, machine,
|
|
214
327
|
ldq.append({'temperature': magtemp,
|
215
328
|
'i1':i1, 'beta':beta,
|
216
329
|
'psid': psid.tolist(), 'psiq': psiq.tolist(),
|
330
|
+
'ld': ld, 'lq': lq,
|
217
331
|
'torque': torque.tolist(),
|
218
332
|
'losses': losses})
|
219
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/multiproc.py
CHANGED
femagtools/plot/nc.py
CHANGED
@@ -14,16 +14,21 @@ DEFAULT_CMAP='viridis'
|
|
14
14
|
"""default colormap (see https://matplotlib.org/stable/users/explain/colors/colormaps.html)"""
|
15
15
|
|
16
16
|
|
17
|
-
def spel(isa, with_axis=False, ax=0):
|
17
|
+
def spel(isa, superelements=[], with_axis=False, ax=0):
|
18
18
|
"""plot super elements of I7/ISA7 model
|
19
19
|
Args:
|
20
20
|
isa: Isa7 object
|
21
|
+
superelements: list of super elements (all if empty)
|
21
22
|
"""
|
22
23
|
from matplotlib.patches import Polygon
|
23
24
|
if ax == 0:
|
24
25
|
ax = plt.gca()
|
25
26
|
ax.set_aspect('equal')
|
26
|
-
|
27
|
+
if superelements:
|
28
|
+
spels = superelements
|
29
|
+
else:
|
30
|
+
spels = isa.superelements
|
31
|
+
for se in spels:
|
27
32
|
ax.add_patch(Polygon([n.xy
|
28
33
|
for nc in se.nodechains
|
29
34
|
for n in nc.nodes],
|
@@ -79,17 +84,16 @@ def _contour(ax, title, elements, values, label='',
|
|
79
84
|
for n in nc.nodes],
|
80
85
|
color='gray', alpha=0.1, lw=0))
|
81
86
|
valid_values = np.logical_not(np.isnan(values))
|
82
|
-
|
83
|
-
|
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]
|
84
89
|
p = PatchCollection(patches, match_original=False,
|
85
90
|
cmap=cmap, alpha=alpha)
|
86
91
|
p.set_array(np.asarray(values)[valid_values])
|
87
92
|
ax.add_collection(p)
|
88
93
|
cb = plt.colorbar(p, shrink=0.9)
|
89
94
|
|
90
|
-
for patch in np.array([Polygon(
|
91
|
-
|
92
|
-
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)]:
|
93
97
|
ax.add_patch(patch)
|
94
98
|
if label:
|
95
99
|
cb.set_label(label=label)
|
@@ -130,9 +134,10 @@ def demag_pos(isa, pos=-1, icur=-1, ibeta=-1, cmap=DEFAULT_CMAP, ax=0):
|
|
130
134
|
x = isa.pos_el_fe_induction[i]
|
131
135
|
|
132
136
|
hpol = demag[:, i]
|
137
|
+
hmax = np.max(hpol)
|
133
138
|
hpol[hpol == 0] = np.nan
|
134
|
-
_contour(ax, f'Demagnetization at pos. {round(x/np.pi*180):.1f}°,'
|
135
|
-
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)',
|
136
141
|
emag, hpol, '-H / kA/m', cmap, isa)
|
137
142
|
logger.info("Max demagnetization %f kA/m", np.nanmax(hpol))
|
138
143
|
|
@@ -232,7 +237,7 @@ def flux_density_pos(isa, ipos, subreg=[], icur=-1, ibeta=-1, cmap=DEFAULT_CMAP,
|
|
232
237
|
for e in elements:
|
233
238
|
fd = isa.flux_density(e, icur, ibeta)
|
234
239
|
b.append(np.linalg.norm(
|
235
|
-
(fd['bx'][ipos], fd['
|
240
|
+
(fd['bx'][ipos], fd['by'][ipos])))
|
236
241
|
fluxd = np.array(b)
|
237
242
|
pos = isa.pos_el_fe_induction[ipos]*180/np.pi
|
238
243
|
isa.rotate(isa.pos_el_fe_induction[ipos])
|
@@ -16,6 +16,15 @@ m.slot_r2 = ${model['slot_r2']*1e3} -- Slot radius [mm]
|
|
16
16
|
m.mcvkey_yoke = mcvkey_yoke
|
17
17
|
m.nodedist = ${model.get('m.nodedist', 1)} -- Node distance
|
18
18
|
|
19
|
+
-- overdeterminate slot_h2
|
20
|
+
if (math.abs(m.slot_h2 - m.slot_r1 - m.slot_h1) > 0) then
|
21
|
+
m.slot_h2 = m.slot_h1 + m.slot_r1
|
22
|
+
end
|
23
|
+
-- overdeterminate slot_open_width
|
24
|
+
if (m.slot_r1 > 0 and math.abs(m.slot_width - 2*m.slot_r1 - m.slot_open_width) > 0) then
|
25
|
+
m.slot_open_width = m.slot_width - 2*m.slot_r1
|
26
|
+
end
|
27
|
+
|
19
28
|
if (m.model_type == "S1R2") or (m.model_type == "S1R2_all") then
|
20
29
|
if (m.st_yoke_height > 0) then
|
21
30
|
m.st_yoke_height = 0
|
@@ -68,7 +77,7 @@ m.nodedist = ${model.get('m.nodedist', 1)} -- Node distance
|
|
68
77
|
|
69
78
|
if (m.slot_r1 > 0) then
|
70
79
|
C1 = fml.Circle:Create(P33,m.slot_r1)
|
71
|
-
P32 = fml.Point:Tangent(P52,C1,
|
80
|
+
P32 = fml.Point:Tangent(P52,C1,1)
|
72
81
|
end
|
73
82
|
|
74
83
|
model_size = m.pole_width*m.num_poles*m.num_slots/m.tot_num_slot
|
@@ -77,7 +86,7 @@ m.nodedist = ${model.get('m.nodedist', 1)} -- Node distance
|
|
77
86
|
|
78
87
|
nc_line(P11.x,P11.y, P51.x,P51.y, 0)
|
79
88
|
nc_line_cont(P52.x, P52.y, 0)
|
80
|
-
if P32 ~= nil then
|
89
|
+
if P32 ~= nil and m.slot_r1 > 0 then
|
81
90
|
nc_line_cont(P32.x, P32.y, 0)
|
82
91
|
nc_circle_m(P23.x,P23.y, P32.x,P32.y, P33.x,P33.y, m.slot_r1, 0)
|
83
92
|
else
|
@@ -33,7 +33,5 @@ post_models("induct(x)","b") -- Calculate field distribution
|
|
33
33
|
until i>=N
|
34
34
|
io.close(data)
|
35
35
|
|
36
|
-
color_gradation(0,0,"tot","Babs",0,0,"")
|
37
36
|
-- experimental (new femag-classic needed)
|
38
|
-
|
39
|
-
add_field_lines("field.svg", 25)
|
37
|
+
export_calc_results('fieldcalc.vtu')
|
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,7 +1,7 @@
|
|
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
|
-
femagtools/amela.py,sha256=
|
4
|
+
femagtools/amela.py,sha256=pHjfXzpANI-7oz8MtrqNcyDZ6PxVM91vCJuvYhHy1rk,13891
|
5
5
|
femagtools/asm.py,sha256=CiL0KWaF4P7O6-VwmGLdva_icwmPrPiI-TFQ19XYTKk,7660
|
6
6
|
femagtools/bch.py,sha256=q6vMKFI0DSMQZDsOPAxMVPoxzz6aAUCApuwcW6c_oXM,70154
|
7
7
|
femagtools/bchxml.py,sha256=KrRjAdrUPZXmiWvonu9HhpG_NvImMBpiXWTL4iSr4kE,3142
|
@@ -15,15 +15,15 @@ femagtools/dakotaout.py,sha256=6nn0PXsB40mPKiQLenqAtHy0KXCO7kvqqQ-aD2JhQvw,5573
|
|
15
15
|
femagtools/docker.py,sha256=XDVmLBB0z4sZZpcrx7Wbm84xl4ksj7aqn5-ZOPxdxm4,7460
|
16
16
|
femagtools/ecloss.py,sha256=boekPeuh3XlfdcEmtbg9IvmxeheX1PFm1ySv9QnY_90,12925
|
17
17
|
femagtools/erg.py,sha256=IXKq76P9qLt_ssNOP78v8Qizk3J2Zg80yaKDSjzwoJE,1224
|
18
|
-
femagtools/femag.py,sha256=
|
18
|
+
femagtools/femag.py,sha256=0XfEiXkfv2MWW6qh3D25Za4Vq9uDP_UIEyHCIBL_wok,42305
|
19
19
|
femagtools/forcedens.py,sha256=nEM1MHxtpLee2sGFsehzrWEdsCRe_RSRqyNfj6u_l8g,7415
|
20
|
-
femagtools/fsl.py,sha256=
|
20
|
+
femagtools/fsl.py,sha256=3jbMaE63DMdm-2GxSFtTjMCfOI-Ql5xASe7L8IohRC8,31377
|
21
21
|
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=
|
26
|
-
femagtools/isa7.py,sha256=
|
25
|
+
femagtools/hxy.py,sha256=PkiZ_-CRhtvtpkmLAP8iMtwvzh7CjKGGcAbOhFb4Nls,6275
|
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
|
29
29
|
femagtools/losscoeffs.py,sha256=dlSYDS13RqpPHLdv_EPWIA9liwhqjbxUiN7t7GFPZhw,5397
|
@@ -32,7 +32,7 @@ femagtools/mcv.py,sha256=Pll-r0YZh-wp9EQBTD4XEBlX4J5jy4oeVa22SYIM7q8,39744
|
|
32
32
|
femagtools/me.py,sha256=XNK0l-aroNYfKyxV_uslE8q3vJb_KuntAYTWd-4FQaQ,1833
|
33
33
|
femagtools/model.py,sha256=wcOZwKe8nd_vwe4SlLmWPe4ukvtVINUE8Qi5HEp2hkw,15018
|
34
34
|
femagtools/moproblem.py,sha256=kOP8pRdD8YXz28_M2WKnFgl3eeJ7tqg49ohoazsmUOg,2825
|
35
|
-
femagtools/multiproc.py,sha256=
|
35
|
+
femagtools/multiproc.py,sha256=7mJF-VU1NrJkENyg8eHtDrDRNBwLPK43phZv3ehm9BU,8435
|
36
36
|
femagtools/mxw2msh.py,sha256=CIIqAvfs8U-A0OfuOAoDaqNSmoMSHSI_tW1CPFRCP5E,2151
|
37
37
|
femagtools/nc.py,sha256=VQKpA2ZLoyvkQmzmHGrG7oePfGvynNw-pwqfavSxJx8,14233
|
38
38
|
femagtools/netlist.py,sha256=CSCl8setLZ_L8DCnNWaNA3-wLe1yo-fmzARZoVvYfaA,2052
|
@@ -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,12 +79,12 @@ 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
|
86
86
|
femagtools/templates/afm_rotor.mako,sha256=fY-dlZvRLN9UAy5V6Q_inWghkSUe8pzrCYjJdNgfNXs,3112
|
87
|
-
femagtools/templates/afm_stator.mako,sha256=
|
87
|
+
femagtools/templates/afm_stator.mako,sha256=l1xEwxffZ1jyx5wuJ3rhVbVlZirJzD2K8n4i5Dvbxuc,5344
|
88
88
|
femagtools/templates/airgapinduc.mako,sha256=aCMLZ7P4vjeSGikIetkwymgDjESdftPN_aYx2LfjfsY,246
|
89
89
|
femagtools/templates/asyn_motor.mako,sha256=vvZ0SIJj4ORaCbE1Hl5NeCU_j2CWdOltVpSKP7ESJTQ,2879
|
90
90
|
femagtools/templates/basic_modpar.mako,sha256=7qXIYrqJqI3xRnxXKG5zSwBNsiQotc94Q37X4sbAXxQ,3036
|
@@ -98,7 +98,7 @@ femagtools/templates/connect_models.mako,sha256=8j1hzBMeoDJ7-GL5BH-S5p53Bu5jtqqs
|
|
98
98
|
femagtools/templates/cu_losses.mako,sha256=EeNwINYuwBuhbo9LH3STdQOTxOyyWw_BANgh_BSV9TE,1339
|
99
99
|
femagtools/templates/ec-rotorbar.mako,sha256=RbA1TVNczEEddTNjvGLPxILExxp4rIgoxXe1YT6a4Is,1672
|
100
100
|
femagtools/templates/fe-contr.mako,sha256=NoP7FQ62ITxgNmwP6GmkCnGhjEn5gPLUFgdLdhkKylY,1983
|
101
|
-
femagtools/templates/fieldcalc.mako,sha256
|
101
|
+
femagtools/templates/fieldcalc.mako,sha256=yZ0_uAtdtzpv1uPjd92zyCbzTLhu2Rvvd5mRaOyesSU,806
|
102
102
|
femagtools/templates/gen_winding.mako,sha256=yRe00f1L4_UuEOVwBkbEOL6rgG8NY43Jbpdud1nw4oo,3834
|
103
103
|
femagtools/templates/inductances.mako,sha256=OpcW3E7LW09J8eoXylzfq2R16LKKxzJDr0PGCdHzixM,560
|
104
104
|
femagtools/templates/ld_lq_fast.mako,sha256=BEQoplL7Ojqg5caldzAhMLKL-3E78wCSSbz5-KkDk2o,1359
|
@@ -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
|