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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  """
4
4
  __title__ = 'femagtools'
5
- __version__ = '1.5.1'
5
+ __version__ = '1.5.2'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2016-2022 SEMAFOR Informatik & Energie AG'
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
- from collections import defaultdict
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
- points = [point(i, np.random.randint(0,K), xy)
96
- for i, xy in enumerate(hxy[0]['e'])]
97
- new_means, new_points = fit(points)
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.coord for p in new_points if p.k == k],
100
- 'pos': [], 'hxy': [], 'bxy': [], 'mxy': []}
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
- hkeys = ['hxy', 'bxy', 'mxy']
103
- for i, h in enumerate(hxy): # all positions
104
- for mag in magnets:
105
- mag['pos'].append(h['pos'])
106
- m = [{k: [] for k in hkeys}
107
- for kk in range(K)]
108
- for p in new_points: # all elements
109
- for k in hkeys:
110
- m[p.k][k].append(h[k][p.k])
111
- for mk, magk in zip(m, magnets):
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()
@@ -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)
@@ -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'], par)
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
@@ -350,21 +350,27 @@ def dqparident(workdir, engine, temp, machine,
350
350
  """
351
351
  import pathlib
352
352
 
353
- da1 = machine['outer_diam']
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
- hs = machine['stator'][slotmodel].get('slot_height', 0)
362
- wdgk = 'windings' if 'windings' in machine else 'winding'
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 = 15 # max current density in A/mm2
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
- patches = np.array([Polygon([v.xy for v in e.vertices])
88
- for e in elements])[valid_values]
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([v.xy for v in e.vertices],
96
- fc='white', alpha=1.0)
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 -{np.max(hpol):.1f} kA/m)',
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 vtk
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
- hey : int (optional) Key of point or cell
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.1
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=WYCiO3Ceu0xELGYtZqE4IhrBuyn7Rm1wM0fZqs7sgaU,1615
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=TU0GoHtStq3VBoc4nGLmtKquY8-tT0UWxLf5FzMBLjE,3738
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=NhbwGGGeRDhvNWA58z-Npm7nylvfOzZcaYtfHHWWjqE,8000
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=QqYs9Qpxmb10UbaLJ1cvNZBIdUgFUTPHtrwNMu63imI,22417
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=BNaYNmZpOz-Q8grCara_hTeen5rbRPqpNcnLr84W9o4,23031
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=oqGE_q1uDZYR6cqo2TPNBh6gw8wBT_TfUlv9QB1FVxo,16698
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=iHU7gb31Hm-se_ArPQqTpJjhPzjraYZN7OKN79hF3Aw,9541
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=UEZV0wLNQhzcXVO1ysfQNXdX-fNIEM98Ya8zFw6gFf8,1109
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=mZe-JDFUv0SDRofx8sH0R8mO2MGf1Evbvvd-Oc5DrRo,872
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.1.dist-info/LICENSE,sha256=V5OED7AzEaOtvbfgNheKOSUeNtijvKQuo84FtSJNkJU,1316
200
- femagtools-1.5.1.dist-info/METADATA,sha256=bnpCv2yda5Fv4hVrSzJXeHnr5wM2jNp9rD9Uj83K_yw,5685
201
- femagtools-1.5.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
202
- femagtools-1.5.1.dist-info/entry_points.txt,sha256=UXpu6KnrykN89sCUaFAIIzn_dYwuxizUS0GcPdoekro,195
203
- femagtools-1.5.1.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
204
- femagtools-1.5.1.dist-info/RECORD,,
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
@@ -15,7 +15,7 @@ def test_im():
15
15
  r = femagtools.machine.sizing.im(P, n, p, udc=udc,
16
16
  sigmas=fs, Ba=0.77,
17
17
  cos_phi=0.8, eta=0.8,
18
- lda=0.9)
18
+ lda=0.9, rtype='statorRotor3')
19
19
  assert round(r['outer_diam'], 3) == 0.19
20
20
  assert r['stator']['num_slots'] == 36
21
21
 
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 vtu_data():
7
- filename = 'src/tests/data/zzz_pm_model_ts_results_1/zzz_pm_model_ts_0000.vtu'
8
- return vtu.read(filename)
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(vtu_data):
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)