femagtools 1.5.7__py3-none-any.whl → 1.6.1__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.
Files changed (40) hide show
  1. femagtools/__init__.py +1 -1
  2. femagtools/bch.py +38 -3
  3. femagtools/dxfsl/area.py +2 -3
  4. femagtools/dxfsl/conv.py +6 -1
  5. femagtools/dxfsl/converter.py +10 -2
  6. femagtools/dxfsl/fslrenderer.py +1 -2
  7. femagtools/dxfsl/functions.py +24 -27
  8. femagtools/dxfsl/geom.py +210 -89
  9. femagtools/dxfsl/machine.py +43 -16
  10. femagtools/dxfsl/plotrenderer.py +2 -2
  11. femagtools/dxfsl/shape.py +84 -19
  12. femagtools/femag.py +21 -3
  13. femagtools/fsl.py +14 -2
  14. femagtools/machine/__init__.py +13 -33
  15. femagtools/machine/afpm.py +22 -21
  16. femagtools/machine/pm.py +22 -21
  17. femagtools/machine/sm.py +1 -1
  18. femagtools/machine/utils.py +112 -58
  19. femagtools/mcv.py +27 -1
  20. femagtools/model.py +4 -2
  21. femagtools/nc.py +7 -0
  22. femagtools/opt.py +1 -1
  23. femagtools/parstudy.py +5 -2
  24. femagtools/plot/__init__.py +1 -0
  25. femagtools/plot/bch.py +2 -0
  26. femagtools/plot/fieldlines.py +37 -0
  27. femagtools/templates/basic_modpar.mako +8 -0
  28. femagtools/templates/bertotti.mako +40 -0
  29. femagtools/templates/modified_steinmetz.mako +39 -0
  30. femagtools/ts.py +1 -1
  31. femagtools/utils.py +9 -3
  32. {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/METADATA +1 -1
  33. {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/RECORD +40 -37
  34. tests/test_bchreader.py +12 -1
  35. tests/test_femag.py +1 -1
  36. tests/test_fsl.py +1 -1
  37. {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/LICENSE +0 -0
  38. {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/WHEEL +0 -0
  39. {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/entry_points.txt +0 -0
  40. {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/top_level.txt +0 -0
@@ -45,7 +45,7 @@ def ld_interpol(i1, beta, v):
45
45
  cur = copy.deepcopy(i1)
46
46
  betad = copy.deepcopy(beta)
47
47
  if np.amin(beta) < -90 and \
48
- np.amax(beta) > -90:
48
+ np.amax(beta) > -90:
49
49
  # motor and generator
50
50
  v[0] = v[1]
51
51
  v[-1] = v[-2]
@@ -53,18 +53,18 @@ def ld_interpol(i1, beta, v):
53
53
  dbeta = np.abs(beta[0][0] - beta[1][0])
54
54
  bp = [[beta[0][0]-dbeta for i in range(len(np.unique(i1)))]] + beta[1:-1] + \
55
55
  [[dbeta for i in range(len(np.unique(i1)))]]
56
- else:
56
+ else:
57
57
  v[-1] = v[-2]
58
58
  dbeta = np.abs(beta[0][0] - beta[1][0])
59
59
  bp = beta[0:-1] + \
60
60
  [[dbeta for i in range(len(np.unique(i1)))]]
61
-
61
+
62
62
  return RectBivariateSpline(np.unique(bp), np.unique(cur), \
63
63
  np.array(v)).ev(*[betad, i1]).tolist()
64
64
 
65
65
  def lq_interpol(i1, beta, v):
66
66
  '''interpolate Lq at beta -90°'''
67
- if -90 not in np.unique(beta):
67
+ if -90 not in np.unique(beta):
68
68
  return v
69
69
  # lq
70
70
  betad = copy.deepcopy(beta)
@@ -75,7 +75,7 @@ def lq_interpol(i1, beta, v):
75
75
  v.pop(inx[0, 0])
76
76
  bp = beta[0:inx[0, 0]] + beta[inx[0, 0]+1:]
77
77
  cp = i1[0:inx[0, 0]] + i1[inx[0, 0]+1:]
78
- else:
78
+ else:
79
79
  v[0] = v[1]
80
80
  dbeta = np.abs(beta[0][0] - beta[1][0])
81
81
  bp = [[-90-dbeta for i in i1[0]]] + beta[1::]
@@ -181,7 +181,7 @@ def parident(workdir, engine, temp, machine,
181
181
  poc=poc.Poc(999),
182
182
  speed=0)
183
183
  logging.info("Noload simulation")
184
- if kwargs.get('use_multiprocessing', True):
184
+ if kwargs.get('use_multiprocessing', True):
185
185
  pstudy = parstudy.List(
186
186
  workdir, condMat=condMat, magnets=magnetMat,
187
187
  magnetizingCurves=magnetizingCurves,
@@ -190,17 +190,17 @@ def parident(workdir, engine, temp, machine,
190
190
  nlresults = pstudy(nlparvardef, machine, nlcalc, engine)
191
191
  if nlresults['status'].count('C') != len(nlresults['status']):
192
192
  raise ValueError('Noload simulation failed %s', nlresults['status'])
193
- else:
193
+ else:
194
194
  nlresults = {"x": [], "f": []}
195
195
  i = 0
196
- for pw, le, sp in zip(pole_width, lfe, linspeed):
196
+ for pw, le, sp in zip(pole_width, lfe, linspeed):
197
197
  nlmachine = {k: machine[k] for k in machine}
198
198
  nlmachine['pole_width'] = pw
199
199
  nlmachine['lfe'] = le
200
200
  nlcalc.update({"speed": sp})
201
201
  nlsubdir = f'{workdir}/{i}'
202
202
  nlworkdir = Path(nlsubdir)
203
- if nlworkdir.exists():
203
+ if nlworkdir.exists():
204
204
  shutil.rmtree(nlworkdir)
205
205
  nlworkdir.mkdir(exist_ok=True)
206
206
  noloadsim = femag.Femag(nlworkdir, condMat=condMat, magnets=magnetMat,
@@ -235,8 +235,8 @@ def parident(workdir, engine, temp, machine,
235
235
  num_move_steps=60,
236
236
  speed=linspeed[i],
237
237
  num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1))
238
-
239
- if kwargs.get('use_multiprocessing', True):
238
+
239
+ if kwargs.get('use_multiprocessing', True):
240
240
  gpstudy = parstudy.Grid(
241
241
  subdir, condMat=condMat, magnets=magnetMat,
242
242
  magnetizingCurves=magnetizingCurves,
@@ -248,7 +248,7 @@ def parident(workdir, engine, temp, machine,
248
248
  domain_beta = np.linspace(beta_min, 0, num_beta_steps).tolist()
249
249
  domain_cur = np.linspace(i1_max/num_cur_steps, i1_max, num_cur_steps).tolist()
250
250
  dir_index = 0
251
- for cur in domain_cur:
251
+ for cur in domain_cur:
252
252
  for be in domain_beta:
253
253
  simulation['angl_i_up'] = be
254
254
  simulation['current'] = cur
@@ -256,7 +256,7 @@ def parident(workdir, engine, temp, machine,
256
256
  subsubdir = subdir + f'/{dir_index}'
257
257
  dir_index = dir_index + 1
258
258
  lworkdir = Path(subsubdir)
259
- if lworkdir.exists():
259
+ if lworkdir.exists():
260
260
  shutil.rmtree(lworkdir)
261
261
  lworkdir.mkdir(exist_ok=True)
262
262
  loadsim = femag.Femag(lworkdir, condMat=condMat, magnets=magnetMat,
@@ -264,7 +264,7 @@ def parident(workdir, engine, temp, machine,
264
264
  cmd=kwargs.get('cmd', None))
265
265
  r = loadsim(mpart, simulation)
266
266
  lresults['f'].append({k: v for k, v in r.items()})
267
-
267
+
268
268
  f = [{k: bch[k]
269
269
  for k in ('linearForce', 'flux', 'losses', 'lossPar')}
270
270
  for bch in lresults['f']]
@@ -288,18 +288,18 @@ def parident(workdir, engine, temp, machine,
288
288
  (-1, num_beta_steps)).T/np.sqrt(2)
289
289
  psiq = np.reshape([r['psiq'] for r in postp],
290
290
  (-1, num_beta_steps)).T/np.sqrt(2)
291
-
291
+
292
292
  ld = np.reshape([r['Ld'] for r in postp],
293
293
  (-1, num_beta_steps)).T.tolist()
294
294
  lq = np.reshape([r['Lq'] for r in postp],
295
295
  (-1, num_beta_steps)).T.tolist()
296
296
  # interpolation ld, lq
297
- curr, angl = [], []
298
- for cr in range(len(beta)):
297
+ curr, angl = [], []
298
+ for cr in range(len(beta)):
299
299
  curr.append(i1)
300
- for al in beta:
300
+ for al in beta:
301
301
  tmp = []
302
- for cr in range(len(i1)):
302
+ for cr in range(len(i1)):
303
303
  tmp.append(al)
304
304
  angl.append(tmp)
305
305
  try:
@@ -307,10 +307,10 @@ def parident(workdir, engine, temp, machine,
307
307
  ld = ld_interpol(xx, yy, ld)
308
308
  xx, yy = copy.deepcopy(curr), copy.deepcopy(angl)
309
309
  lq = lq_interpol(xx, yy, lq)
310
- except:
310
+ except:
311
311
  ld = np.zeros_like(psid).tolist()
312
312
  lq = np.zeros_like(psid).tolist()
313
-
313
+
314
314
  torque = np.reshape([r['torque'] for r in postp],
315
315
  (-1, num_beta_steps)).T
316
316
  losses = {k: np.flip(np.reshape([r['plfe'][k] for r in postp],
@@ -547,6 +547,7 @@ def wdg_resistance(wdg, n, g, aw, outer_diam, inner_diam,
547
547
  def _get_copper_losses(scale_factor, bch):
548
548
  """return copper losses from bch files"""
549
549
  try:
550
+ wdgk = 'winding'
550
551
  cu_losses = sum([b['losses'][0][wdgk] for b in bch])
551
552
  return scale_factor*cu_losses
552
553
  except KeyError:
femagtools/machine/pm.py CHANGED
@@ -638,10 +638,10 @@ class PmRelMachine(object):
638
638
  'rotor_hyst': hf[1],
639
639
  'rotor_eddy': ef[1]}
640
640
  # 'magnet'):
641
- if 'styoke_exc' in pfe:
642
- self.plexp.update({'styoke_exc': cf[0],
643
- 'stteeth_exc':cf[0],
644
- 'rotor_exc': cf[1]})
641
+ if 'styoke_excess' in pfe:
642
+ self.plexp.update({'styoke_excess': cf[0],
643
+ 'stteeth_excess':cf[0],
644
+ 'rotor_excess': cf[1]})
645
645
 
646
646
  def betai1_plcu(self, i1, w1=0):
647
647
  return self.m*self.rstat(w1)*i1**2
@@ -1143,15 +1143,16 @@ class PmRelMachineLdq(PmRelMachine):
1143
1143
  kx = len(beta)-1
1144
1144
  try:
1145
1145
  pfe = kwargs['losses']
1146
- if 'styoke_exc' in pfe:
1146
+ if 'styoke_excess' in pfe and np.any(pfe['styoke_excess']):
1147
1147
  self.bertotti = True
1148
- self.losskeys += ['styoke_exc',
1149
- 'stteeth_exc',
1150
- 'rotor_exc']
1148
+ self.losskeys += ['styoke_excess',
1149
+ 'stteeth_excess',
1150
+ 'rotor_excess']
1151
1151
  self._set_losspar(pfe)
1152
1152
  self._losses = {k: ip.RectBivariateSpline(
1153
1153
  beta, i1, np.array(pfe[k]),
1154
- kx=kx, ky=ky).ev for k in tuple(self.losskeys)}
1154
+ kx=kx, ky=ky).ev for k in self.losskeys
1155
+ if k in pfe}
1155
1156
  except KeyError as e:
1156
1157
  logger.warning("loss map missing: %s", e)
1157
1158
  pass
@@ -1238,12 +1239,12 @@ class PmRelMachineLdq(PmRelMachine):
1238
1239
 
1239
1240
  def betai1_plfe1(self, beta, i1, f1):
1240
1241
  stator_losskeys = ['styoke_eddy', 'styoke_hyst',
1241
- 'stteeth_eddy', 'stteeth_hyst']
1242
+ 'stteeth_eddy', 'stteeth_hyst']
1242
1243
  if self.bertotti:
1243
- stator_losskeys += ['styoke_exc', 'stteeth_exc']
1244
+ stator_losskeys += ['styoke_excess', 'stteeth_excess']
1244
1245
  return np.sum([
1245
- self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k] for
1246
- k in tuple(stator_losskeys)], axis=0)
1246
+ self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k]
1247
+ for k in stator_losskeys if k in self._losses], axis=0)
1247
1248
 
1248
1249
  def iqd_plfe1(self, iq, id, f1):
1249
1250
  return self.betai1_plfe1(*betai1(iq, id), f1)
@@ -1251,7 +1252,7 @@ class PmRelMachineLdq(PmRelMachine):
1251
1252
  def betai1_plfe2(self, beta, i1, f1):
1252
1253
  rotor_losskeys = ['rotor_eddy', 'rotor_hyst']
1253
1254
  if self.bertotti:
1254
- rotor_losskeys += ['rotor_exc']
1255
+ rotor_losskeys += ['rotor_excess']
1255
1256
  return np.sum([
1256
1257
  self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k] for
1257
1258
  k in tuple(rotor_losskeys)], axis=0)
@@ -1295,7 +1296,7 @@ class PmRelMachinePsidq(PmRelMachine):
1295
1296
  self.iqrange = (min(iq), max(iq))
1296
1297
  self.betarange = (-np.pi if min(iq) < 0 else -np.pi/2,
1297
1298
  0 if max(iq) > 0 else -np.pi/2)
1298
- self.i1range = (0, np.sqrt(2)*np.min(id))
1299
+ self.i1range = (0, betai1(np.max(iq), 0)[1])
1299
1300
  self.io = np.max(iq)/2, np.min(id)/2
1300
1301
 
1301
1302
  if np.any(psid.shape < (4, 4)):
@@ -1322,11 +1323,11 @@ class PmRelMachinePsidq(PmRelMachine):
1322
1323
  self._psiq = ip.RectBivariateSpline(iq, id, psiq).ev
1323
1324
  try:
1324
1325
  pfe = kwargs['losses']
1325
- if 'styoke_exc' in pfe:
1326
+ if 'styoke_excess' in pfe and np.any(pfe['styoke_excess']):
1326
1327
  self.bertotti = True
1327
- self.losskeys += ['styoke_exc',
1328
- 'stteeth_exc',
1329
- 'rotor_exc']
1328
+ self.losskeys += ['styoke_excess',
1329
+ 'stteeth_excess',
1330
+ 'rotor_excess']
1330
1331
  self._set_losspar(pfe)
1331
1332
  self._losses = {k: ip.RectBivariateSpline(
1332
1333
  iq, id, np.array(pfe[k])).ev for k in (
@@ -1385,7 +1386,7 @@ class PmRelMachinePsidq(PmRelMachine):
1385
1386
  stator_losskeys = ['styoke_eddy', 'styoke_hyst',
1386
1387
  'stteeth_eddy', 'stteeth_hyst']
1387
1388
  if self.bertotti:
1388
- stator_losskeys += ['styoke_exc', 'stteeth_exc']
1389
+ stator_losskeys += ['styoke_excess', 'stteeth_excess']
1389
1390
  return np.sum([
1390
1391
  self._losses[k](iq, id)*(f1/self.fo)**self.plexp[k] for
1391
1392
  k in tuple(stator_losskeys)], axis=0)
@@ -1396,7 +1397,7 @@ class PmRelMachinePsidq(PmRelMachine):
1396
1397
  def iqd_plfe2(self, iq, id, f1):
1397
1398
  rotor_losskeys = ['rotor_eddy', 'rotor_hyst']
1398
1399
  if self.bertotti:
1399
- rotor_losskeys += ['rotor_exc']
1400
+ rotor_losskeys += ['rotor_excess']
1400
1401
  return np.sum([
1401
1402
  self._losses[k](iq, id)*(f1/self.fo)**self.plexp[k] for
1402
1403
  k in tuple(rotor_losskeys)], axis=0)
femagtools/machine/sm.py CHANGED
@@ -546,7 +546,7 @@ class SynchronousMachine(object):
546
546
  w10)[0]
547
547
 
548
548
  def characteristics(self, T, n, u1max, nsamples=50,
549
- with_tmech=True, with_torque_corr=False):
549
+ with_tmech=True, with_torque_corr=False, **kwargs):
550
550
  """calculate torque speed characteristics.
551
551
  return dict with list values of
552
552
  n, T, u1, i1, beta, cosphi, pmech, n_type
@@ -303,11 +303,12 @@ def dqpar_interpol(xfit, dqpars, ipkey='temperature'):
303
303
  else:
304
304
  fpip[k] = ip.interp1d(
305
305
  x, m, fill_value='extrapolate')(xfit).T
306
- try:
307
- for k in ('styoke_hyst', 'stteeth_hyst',
308
- 'styoke_eddy', 'stteeth_eddy',
309
- 'rotor_hyst', 'rotor_eddy',
310
- 'magnet'):
306
+
307
+ for k in ('styoke_hyst', 'stteeth_hyst',
308
+ 'styoke_eddy', 'stteeth_eddy',
309
+ 'rotor_hyst', 'rotor_eddy',
310
+ 'magnet'):
311
+ try:
311
312
  m = np.array([f['losses'][k] for f in sorted_dqpars]).T
312
313
  if len(x) > 2:
313
314
  fpip['losses'][k] = np.array(
@@ -316,12 +317,13 @@ def dqpar_interpol(xfit, dqpars, ipkey='temperature'):
316
317
  else:
317
318
  fpip['losses'][k] = ip.interp1d(
318
319
  x, m, fill_value='extrapolate')(xfit).T
319
- fpip['losses']['speed'] = dqpars[0]['losses']['speed']
320
- for f in ('hf', 'ef'):
321
- if f in dqpars[0]['losses']:
322
- fpip['losses'][f] = dqpars[0]['losses'][f]
323
- except KeyError:
324
- pass
320
+ except KeyError:
321
+ pass
322
+
323
+ fpip['losses']['speed'] = dqpars[0]['losses']['speed']
324
+ for f in ('hf', 'ef'):
325
+ if f in dqpars[0]['losses']:
326
+ fpip['losses'][f] = dqpars[0]['losses'][f]
325
327
  return x, fpip
326
328
 
327
329
 
@@ -351,52 +353,70 @@ def dqparident(workdir, engine, temp, machine,
351
353
  import pathlib
352
354
 
353
355
  wdgk = 'windings' if 'windings' in machine else 'winding'
354
- da1 = machine['bore_diam']
355
- Q1 = machine['stator']['num_slots']
356
+ def create_wdg(machine):
357
+ wpar = {'Q': machine['stator']['num_slots'],
358
+ 'm': machine[wdgk]['num_phases'],
359
+ 'p': machine['poles']//2}
360
+
361
+ if 'coil_span' in machine[wdgk]:
362
+ wpar['yd'] = machine[wdgk]['coil_span']
363
+ if 'num_layers' in machine[wdgk]:
364
+ wpar['l'] = machine[wdgk]['num_layers']
365
+
366
+ return windings.Winding(wpar)
367
+ try:
368
+ defspeed = 160/machine['poles']
369
+ except KeyError:
370
+ if kwargs.get('speed', 0) == 0:
371
+ raise ValueError('rated speed missing')
372
+ defspeed = kwargs['speed']
373
+
356
374
  lfe = machine['lfe']
357
375
  g = machine[wdgk].get('num_par_wdgs', 1)
358
- slotmodel = [k for k in machine['stator'] if isinstance(
359
- machine['stator'][k], dict)][-1]
360
- if slotmodel == 'stator1':
361
- hs = machine['stator']['stator1']['slot_rf1'] - \
362
- machine['stator']['stator1']['tip_rh1']
363
- else:
364
- dy1 = machine['outer_diam']
365
- hs = machine['stator'][slotmodel].get(
366
- 'slot_height', 0.6*(dy1-da1)/2)
367
-
368
376
  N = machine[wdgk]['num_wires']
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
377
+ if 'cufilfact' in machine[wdgk]:
378
+ fcu = machine[wdgk]['cufilfact']
379
+ elif 'fillfac' in machine[wdgk]:
380
+ fcu = machine[wdgk]['fillfac']
381
+ else:
382
+ fcu = 0.42
383
+
384
+ try: # calc basic dimensions if not fsl or dxf model
385
+ Q1 = machine['stator']['num_slots']
386
+ da1 = machine['bore_diam']
387
+ slotmodel = [k for k in machine['stator'] if isinstance(
388
+ machine['stator'][k], dict)][-1]
389
+ if slotmodel == 'stator1':
390
+ hs = machine['stator']['stator1']['slot_rf1'] - \
391
+ machine['stator']['stator1']['tip_rh1']
392
+ else:
393
+ dy1 = machine['outer_diam']
394
+ hs = machine['stator'][slotmodel].get(
395
+ 'slot_height', 0.6*(dy1-da1)/2)
373
396
 
374
- period_frac = kwargs.get('period_frac', 6)
375
- if machine.get('external_rotor', False):
376
- period_frac = 1 # TODO: missing femag support
397
+ Jmax = 30e6 # max current density in A/m2
398
+ Acu = fcu*0.5*np.pi*(da1+hs)*hs
399
+ i1_max = round(Acu/Q1/N*Jmax/10)*10
400
+ except KeyError:
401
+ if kwargs.get('i1_max', 0) == 0:
402
+ raise ValueError('i1_max missing')
403
+ i1_max = kwargs['i1_max']
377
404
 
378
405
  # winding resistance
379
- wpar = {'Q': machine['stator']['num_slots'],
380
- 'm': machine[wdgk]['num_phases'],
381
- 'p': machine['poles']//2}
382
-
383
- if 'coil_span' in machine[wdgk]:
384
- wpar['yd'] = machine[wdgk]['coil_span']
385
- if 'num_layers' in machine[wdgk]:
386
- wpar['l'] = machine[wdgk]['num_layers']
387
-
388
- wdg = windings.Winding(wpar)
389
-
390
- if 'wire_gauge' in machine[wdgk]:
391
- aw = machine[wdgk]['wire_gauge']
392
- elif 'dia_wire' in machine[wdgk]:
393
- aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
394
- elif ('wire_width' in machine[wdgk]) and ('wire_height' in machine[wdgk]):
395
- aw = machine['windings']['wire_width']*machine[wdgk]['wire_height']
396
- else: # wire diameter from slot area
397
- aw = 0.75 * machine[wdgk].get('cufilfact', 0.45)*\
398
- np.pi*da1*hs/Q1/wpar['l']/N
399
- r1 = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
406
+ try:
407
+ wdg = create_wdg(machine)
408
+
409
+ if 'wire_gauge' in machine[wdgk]:
410
+ aw = machine[wdgk]['wire_gauge']
411
+ elif 'dia_wire' in machine[wdgk]:
412
+ aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
413
+ elif ('wire_width' in machine[wdgk]) and ('wire_height' in machine[wdgk]):
414
+ aw = machine['windings']['wire_width']*machine[wdgk]['wire_height']
415
+ else: # wire diameter from slot area
416
+ aw = 0.75 * fcu * np.pi*da1*hs/Q1/wdg.l/N
417
+ r1 = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
418
+ except (NameError, KeyError):
419
+ r1 = 0 # cannot calc winding resistance
400
420
 
401
421
  n = len(temp)
402
422
  parvardef = {
@@ -415,6 +435,10 @@ def dqparident(workdir, engine, temp, machine,
415
435
  leakfile = pathlib.Path(workdir) / 'end_wind_leak.dat'
416
436
  leakfile.unlink(missing_ok=True)
417
437
 
438
+ period_frac = kwargs.get('period_frac', 6)
439
+ if machine.get('external_rotor', False):
440
+ period_frac = 1 # TODO: missing femag support
441
+
418
442
  simulation = dict(
419
443
  calculationMode='ld_lq_fast',
420
444
  i1_max=kwargs.get('i1_max', i1_max),
@@ -426,12 +450,15 @@ def dqparident(workdir, engine, temp, machine,
426
450
  num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1),
427
451
  num_cur_steps=kwargs.get('num_cur_steps', 5),
428
452
  num_beta_steps=kwargs.get('num_beta_steps', 7),
429
- speed=kwargs.get('speed', 160/machine['poles']),
453
+ speed=kwargs.get('speed', defspeed),
430
454
  period_frac=period_frac)
431
455
 
432
456
  # TODO: cleanup() # remove previously created files in workdir
433
457
  # start calculation
434
458
  results = parvar(parvardef, machine, simulation, engine)
459
+ if 'poles' not in machine:
460
+ machine['poles'] = 2*results['f'][0]['machine']['p']
461
+ da1 = 2*results['f'][0]['machine']['fc_radius']
435
462
  #import json
436
463
  #with open('results.json', 'w') as fp:
437
464
  # json.dump(results, fp)
@@ -457,14 +484,25 @@ def dqparident(workdir, engine, temp, machine,
457
484
  np.array(results['f'][i]['ldq'][k]))).tolist()
458
485
  for k in ('psid', 'psiq', 'torque', 'ld', 'lq', 'psim')})
459
486
  ldq.append(d)
460
- losskeys = ('styoke_hyst', 'stteeth_hyst', 'styoke_eddy',
461
- 'stteeth_eddy', 'rotor_hyst', 'rotor_eddy',
462
- 'magnet')
487
+ # collect existing losses only
488
+ losskeymap = {'magnet': 'magnet'}
489
+ losskeys = [k for k in results['f'][0]['ldq']['losses']
490
+ if len(k.split('_')) > 1] + ['magnet']
491
+ for k in losskeys:
492
+ if k.find('_') > -1:
493
+ pref, post = k.split('_')
494
+ if pref.lower() == 'stza':
495
+ losskeymap[k] = 'stteeth_'+post
496
+ elif pref.lower() == 'stjo':
497
+ losskeymap[k] = 'styoke_'+post
498
+ else:
499
+ losskeymap[k] = k
463
500
  for i in range(0, len(results['f']), 2):
464
501
  j = i//2
465
502
  ldq[j]['temperature'] = results['x'][0][i]
466
- ldq[j]['losses'] = {k: np.vstack((np.array(results['f'][i+1]['ldq']['losses'][k])[:-1, :],
467
- np.array(results['f'][i]['ldq']['losses'][k]))).tolist()
503
+ ldq[j]['losses'] = {losskeymap[k]: np.vstack(
504
+ (np.array(results['f'][i+1]['ldq']['losses'][k])[:-1, :],
505
+ np.array(results['f'][i]['ldq']['losses'][k]))).tolist()
468
506
  for k in losskeys}
469
507
  ldq[j]['losses']['speed'] = results['f'][i]['ldq']['losses']['speed']
470
508
  for k in ('hf', 'ef'):
@@ -473,10 +511,26 @@ def dqparident(workdir, engine, temp, machine,
473
511
  dqpars = {
474
512
  'm': machine[wdgk]['num_phases'],
475
513
  'p': machine['poles']//2,
476
- 'r1': machine[wdgk].get('resistance', r1),
477
514
  'ls1': ls1,
478
515
  "rotor_mass": rotor_mass, "kfric_b": 1,
479
516
  'ldq': ldq}
517
+ if 'resistance' in machine[wdgk]:
518
+ dqpars['r1'] = machine[wdgk]['resistance']
519
+ else:
520
+ if r1:
521
+ dqpars['r1'] = r1
522
+ else:
523
+ from .. import nc
524
+ model = nc.read(str(pathlib.Path(workdir) / machine['name']))
525
+ Q1 = model.num_slots
526
+ #machine['stator']['num_slots'] = Q1
527
+ wdg = create_wdg(machine)
528
+ istat = 0 if model.get_areas()[0]['slots'] else 1
529
+ asl = model.get_areas()[istat]['slots']
530
+ # diameter of wires
531
+ aw = fcu*asl/Q1/wdg.l/N
532
+ hs = asl/(np.pi*da1/3)
533
+ dqpars['r1'] = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
480
534
 
481
535
  if 'current_angles' in results['f'][0]:
482
536
  dqpars['current_angles'] = results['f'][0]['current_angles']
femagtools/mcv.py CHANGED
@@ -50,6 +50,7 @@ transl = dict(
50
50
  rho='mc1_fe_spez_weigth',
51
51
  ch='mc1_ch_factor',
52
52
  cw='mc1_cw_factor',
53
+ ce='mc1_ce_factor',
53
54
  ch_freq='mc1_ch_freq_factor',
54
55
  cw_freq='mc1_cw_freq_factor',
55
56
  fillfac='mc1_fillfac',
@@ -58,6 +59,7 @@ transl = dict(
58
59
  bsat='mc1_bsat',
59
60
  Bo='mc1_base_induction',
60
61
  b_coeff='mc1_induction_factor',
62
+ b_beta_coeff='mc1_induction_beta_factor',
61
63
  fo='mc1_base_frequency',
62
64
  curve=[dict(
63
65
  hi='mc1_hi',
@@ -227,9 +229,12 @@ class Mcv(object):
227
229
  self.MC1_BASE_INDUCTION = 1.5
228
230
  self.MC1_CH_FACTOR = 0.0
229
231
  self.MC1_CW_FACTOR = 0.0
232
+ self.MC1_CE_FACTOR = 0.0
230
233
  self.MC1_CH_FREQ_FACTOR = 0.0
231
234
  self.MC1_CW_FREQ_FACTOR = 0.0
232
235
  self.MC1_INDUCTION_FACTOR = 0.0
236
+ self.MC1_INDUCTION_BETA_FACTOR = 0.0
237
+
233
238
  self.MC1_FE_SPEZ_WEIGTH = 7.65
234
239
  self.MC1_FE_SAT_MAGNETIZATION = 2.15
235
240
 
@@ -237,9 +242,11 @@ class Mcv(object):
237
242
  self.mc1_base_induction = self.MC1_BASE_INDUCTION
238
243
  self.mc1_ch_factor = self.MC1_CH_FACTOR
239
244
  self.mc1_cw_factor = self.MC1_CW_FACTOR
245
+ self.mc1_ce_factor = self.MC1_CE_FACTOR
240
246
  self.mc1_ch_freq_factor = self.MC1_CH_FREQ_FACTOR
241
247
  self.mc1_cw_freq_factor = self.MC1_CW_FREQ_FACTOR
242
248
  self.mc1_induction_factor = self.MC1_INDUCTION_FACTOR
249
+ self.mc1_induction_beta_factor = self.MC1_INDUCTION_BETA_FACTOR
243
250
  self.mc1_fe_spez_weigth = self.MC1_FE_SPEZ_WEIGTH
244
251
  self.mc1_fe_sat_magnetization = self.MC1_FE_SAT_MAGNETIZATION
245
252
 
@@ -519,6 +526,13 @@ class Writer(Mcv):
519
526
  float(self.mc1_fe_sat_magnetization)])
520
527
 
521
528
  if not hasattr(self, 'losses') or not self.losses:
529
+ # new variables: ce factor for bertotti losses
530
+ # b_beta_coeff for modified steinmetz
531
+ try:
532
+ self.writeBlock([float(self.mc1_ce_factor),
533
+ float(self.mc1_induction_beta_factor)])
534
+ except:
535
+ pass
522
536
  return
523
537
 
524
538
  try:
@@ -585,7 +599,7 @@ class Writer(Mcv):
585
599
  logger.info('Losses n freq %d n ind %d', nfreq, nind)
586
600
  except Exception as e:
587
601
  logger.error("Exception %s", e, exc_info=True)
588
-
602
+
589
603
  def writeMcv(self, filename, fillfac=None, recsin=''):
590
604
  # windows needs this strip to remove '\r'
591
605
  filename = filename.strip()
@@ -857,6 +871,16 @@ class Reader(Mcv):
857
871
  if not self.losses['f'] or not self.losses['pfe']:
858
872
  self.losses = {}
859
873
 
874
+ self.ce = 0
875
+ self.b_beta_coeff = 0
876
+ try:
877
+ if not self.losses['f'][0]:
878
+ self.fp.seek(-16, 1)
879
+ res = self.readBlock([float]*2)
880
+ self.ce, self.b_beta_coeff = res[0], res[1]
881
+ except:
882
+ pass
883
+
860
884
  def get_results(self):
861
885
  result = {
862
886
  'name': self.name,
@@ -873,6 +897,8 @@ class Reader(Mcv):
873
897
  'ch': self.ch,
874
898
  'ch_freq': self.ch_freq,
875
899
  'cw': self.cw,
900
+ 'ce': self.ce,
901
+ 'b_beta_coeff': self.b_beta_coeff,
876
902
  'cw_freq': self.cw_freq,
877
903
  'b_coeff': self.b_coeff,
878
904
  'rho': self.rho,
femagtools/model.py CHANGED
@@ -379,6 +379,7 @@ class MachineModel(Model):
379
379
  def rotortype(self):
380
380
  """return type of rotor slot"""
381
381
  for k in self.rotor:
382
+ # anything that is a dict must represent the type
382
383
  if isinstance(self.rotor[k], dict):
383
384
  return k
384
385
  raise AttributeError("Missing rotor model in {}".format(self.magnet))
@@ -386,8 +387,9 @@ class MachineModel(Model):
386
387
  def magnettype(self):
387
388
  """return type of magnet slot"""
388
389
  for k in self.magnet:
389
- if k != 'material' and isinstance(self.magnet[k], dict):
390
- return k
390
+ if k not in {'material', 'temp_prop'}:
391
+ if isinstance(self.magnet[k], dict):
392
+ return k
391
393
  raise AttributeError("Missing magnet model in {}".format(self.magnet))
392
394
 
393
395
  def is_complete(self):
femagtools/nc.py CHANGED
@@ -262,6 +262,7 @@ class Reader(object):
262
262
  ce_ind_exp = 1.5
263
263
  ke = 0.0
264
264
  khml = 0.65
265
+ cw_ind_beta_exp = 0
265
266
 
266
267
  lctype = ['magn_curve']*lmc + ['Outside', 'Inside']
267
268
  for i in range(lmc+2):
@@ -280,6 +281,11 @@ class Reader(object):
280
281
  cw = float(mcgrp.variables['cw'][i].data)
281
282
  cw_freq_exp = float(mcgrp.variables['cw_exp'][i].data)
282
283
  cw_ind_exp = float(mcgrp.variables['ind_exp'][i].data)
284
+ try:
285
+ ce = float(mcgrp.variables['ce'][i].data)
286
+ cw_ind_beta_exp = float(mcgrp.variables['ind_beta_exp'][i].data)
287
+ except:
288
+ pass
283
289
  spec_weight = float(mcgrp.variables['spec_weight'][i].data)
284
290
  fillfactor = float(mcgrp.variables['fillfac'][i].data)
285
291
  shapefactor = 1.0
@@ -327,6 +333,7 @@ class Reader(object):
327
333
  "cw_freq_exp": cw_freq_exp,
328
334
  "cw_ind_exp": cw_ind_exp,
329
335
  "ce": ce,
336
+ "cw_ind_beta_exp": cw_ind_beta_exp,
330
337
  "ce_freq_exp": ce_freq_exp,
331
338
  "ce_ind_exp": ce_ind_exp,
332
339
  "ke": ke,
femagtools/opt.py CHANGED
@@ -82,7 +82,7 @@ class Optimizer(object):
82
82
  task.add_file(self.fea['pocfilename'],
83
83
  self.fea['poc'].content())
84
84
  if 'stateofproblem' in self.fea:
85
- task.set_stateofproblem(fea['stateofproblem'])
85
+ task.set_stateofproblem(self.fea['stateofproblem'])
86
86
  tstart = time.time()
87
87
  ntasks = engine.submit()
88
88
  status = engine.join()
femagtools/parstudy.py CHANGED
@@ -181,10 +181,13 @@ class ParameterStudy(object):
181
181
  simulation['lfe'] = model.lfe
182
182
  simulation['move_action'] = model.move_action
183
183
  simulation['phi_start'] = 0.0
184
- simulation['range_phi'] = 720/model.get('poles')
184
+ try:
185
+ simulation['range_phi'] = 720/model.get('poles')
186
+ except AttributeError: # if dxf or pure fsl model
187
+ simulation['range_phi'] = 0.0
185
188
  simulation.update(model.winding)
186
189
  if 'pocfilename' not in simulation:
187
- simulation['pocfilename'] = f"{model.name}_{model.poles}p.poc"
190
+ simulation['pocfilename'] = f"{model.name}.poc"
188
191
  fea = femagtools.model.FeaModel(simulation)
189
192
 
190
193
  prob = femagtools.moproblem.FemagMoProblem(decision_vars,