femagtools 1.7.2__py3-none-any.whl → 1.7.4__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.7.2'
5
+ __version__ = '1.7.4'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2023-2024 Gamma Technology'
femagtools/airgap.py CHANGED
@@ -52,3 +52,14 @@ def read(filename, pmod=0):
52
52
  return(dict())
53
53
 
54
54
  return fft(bag[0], bag[1], pmod)
55
+
56
+ if __name__ == '__main__':
57
+ import sys
58
+ import matplotlib.pyplot as plt
59
+ import femagtools.plot.fluxdens
60
+ ag = read(sys.argv[1])
61
+ fig, axs = plt.subplots(nrows=2)
62
+ femagtools.plot.fluxdens.airgap(ag, ax=axs[0])
63
+ femagtools.plot.fluxdens.airgap_fft(ag, ax=axs[1])
64
+ fig.tight_layout()
65
+ plt.show()
femagtools/bch.py CHANGED
@@ -70,7 +70,7 @@ def sttylosses(losses):
70
70
  except KeyError:
71
71
  pass
72
72
  return d
73
-
73
+
74
74
  if sregs == {'StYoke', 'StTeeth'}:
75
75
  return hysteddy('StYoke', 'StTeeth', losses)
76
76
  if sregs == {'StJo', 'StZa'}:
@@ -95,11 +95,12 @@ def sttylosses(losses):
95
95
  return l
96
96
  return {}
97
97
 
98
- def losses_mapping_external_rotor(losses):
98
+ def losses_mapping_external_rotor(losses):
99
99
  styoke = 'rotor'
100
- rotor = 'Iron'
100
+ rotor = 'Iron'
101
101
  d = {}
102
102
  try:
103
+ d['styoke'] = losses[styoke]
103
104
  d['styoke_hyst'] = losses[styoke+'_hyst']
104
105
  d['rotor_hyst'] = losses[rotor+'_hyst']
105
106
  d['styoke_eddy'] = losses[styoke+'_eddy']
@@ -1045,7 +1046,7 @@ class Reader:
1045
1046
  '''
1046
1047
  diff = np.floor(np.abs(np.diff(idList)))
1047
1048
  if idList[-1] == 0 and len(idList) > 2 and \
1048
- not np.all(diff == diff[0]):
1049
+ diff[-1] == 0:
1049
1050
  idList = idList[:-1]
1050
1051
  return idList
1051
1052
 
@@ -1061,7 +1062,8 @@ class Reader:
1061
1062
  m.append([floatnan(x) for x in rec])
1062
1063
 
1063
1064
  m = np.array(m).T
1064
- ncols = np.argmax(np.abs(m[1][1:]-m[1][:-1]))+1
1065
+ d = np.diff(m[1])
1066
+ ncols = (len(d)+1)//(len(d[d < 0])+1)
1065
1067
  if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]: # simple correction
1066
1068
  ncols = 2
1067
1069
  iq = np.reshape(m[1], (-1, ncols))[0]
@@ -1070,7 +1072,8 @@ class Reader:
1070
1072
  ncols = ncols-1
1071
1073
 
1072
1074
  id = np.reshape(m[0], (-1, ncols)).T[0]
1073
- id = self.__removeTrailingZero(id)
1075
+ if id[0] >= 0:
1076
+ id = self.__removeTrailingZero(id)
1074
1077
  nrows = len(id)
1075
1078
  if nrows > 1 and id[nrows-1] < id[nrows-2]:
1076
1079
  nrows = nrows-1
@@ -1095,7 +1098,8 @@ class Reader:
1095
1098
  m.append([floatnan(x) for x in rec])
1096
1099
 
1097
1100
  m = np.array(m).T
1098
- ncols = np.argmax(np.abs(m[1][1:]-m[1][:-1]))+1
1101
+ d = np.diff(m[1])
1102
+ ncols = (len(d)+1)//(len(d[d < 0])+1)
1099
1103
  if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]: # simple correction
1100
1104
  ncols = 2
1101
1105
  iq = np.linspace(np.min(m[1]), np.max(m[1]), ncols)
@@ -1104,7 +1108,8 @@ class Reader:
1104
1108
  ncols = ncols-1
1105
1109
 
1106
1110
  id = np.reshape(m[0], (-1, ncols)).T[0]
1107
- id = self.__removeTrailingZero(id)
1111
+ if id[0] >= 0:
1112
+ id = self.__removeTrailingZero(id)
1108
1113
  nrows = len(id)
1109
1114
  if nrows > 1 and id[nrows-1] < id[nrows-2]:
1110
1115
  nrows = nrows-1
@@ -1167,7 +1172,7 @@ class Reader:
1167
1172
  for name in content[2].split('\t') if name][2:]
1168
1173
  # outer rotor motor
1169
1174
  if 'Iron' in subregs and \
1170
- 'Rotor' in subregs:
1175
+ 'Rotor' in subregs:
1171
1176
  self.external_rotor = True
1172
1177
  logger.info("Stator Subregions: %s", subregs)
1173
1178
  speed = float(content[0].split()[-1])/60.
@@ -1183,7 +1188,11 @@ class Reader:
1183
1188
  if not m:
1184
1189
  return
1185
1190
  m = np.array(m).T
1186
- ncols = np.argmax(np.abs(m[1][1:]-m[1][:-1]))+1
1191
+ d = np.diff(m[1])
1192
+ if self.ldq:
1193
+ ncols = (len(d)+1)//(len(d[d > 0])+1)
1194
+ else:
1195
+ ncols = (len(d)+1)//(len(d[d < 0])+1)
1187
1196
  if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]:
1188
1197
  ncols = 2
1189
1198
  id = np.reshape(m[0], (-1, ncols)).T[0]
@@ -1228,9 +1237,9 @@ class Reader:
1228
1237
  (nrows, ncols)).T.tolist()
1229
1238
  for k, v in zip(cols, m[2:])})
1230
1239
  ls['speed'] = speed
1231
- if self.external_rotor:
1240
+ if self.external_rotor:
1232
1241
  ls.update(losses_mapping_external_rotor(ls))
1233
- else:
1242
+ else:
1234
1243
  ls.update(sttylosses(ls))
1235
1244
  if self.ldq:
1236
1245
  self.ldq['losses'] = ls
@@ -1486,9 +1495,9 @@ class Reader:
1486
1495
  def __read_losses(self, content):
1487
1496
  losses = {}
1488
1497
  i = 0
1489
- # check if external rotor
1498
+ # check if external rotor
1490
1499
  if self.weights[0][1] == 0.0 and \
1491
- self.weights[0][-1] > 0:
1500
+ self.weights[0][-1] > 0:
1492
1501
  self.external_rotor = True
1493
1502
  # find results for angle:
1494
1503
  while True:
@@ -1547,8 +1556,8 @@ class Reader:
1547
1556
  losses['total'] += losses['staza']+losses['stajo']
1548
1557
  elif len(rec) == 1:
1549
1558
  t = l.split(':')[-1].strip()
1550
- if t == 'Iron':
1551
- if self.external_rotor:
1559
+ if t == 'Iron':
1560
+ if self.external_rotor:
1552
1561
  losses['rotfe'] = floatnan(rec[0])
1553
1562
  losses['total'] += losses['rotfe']
1554
1563
  else:
@@ -1560,14 +1569,14 @@ class Reader:
1560
1569
  continue
1561
1570
 
1562
1571
  if _rotloss.search(l):
1563
- if l.find('StZa') > -1:
1572
+ if l.find('StZa') > -1:
1564
1573
  self.external_rotor = True
1565
1574
  rec = self.__findNums(content[i+2])
1566
1575
  if len(rec) == 1:
1567
- if self.external_rotor:
1576
+ if self.external_rotor:
1568
1577
  losses['staza'] = floatnan(rec[0])
1569
1578
  losses['total'] += losses['staza']
1570
- else:
1579
+ else:
1571
1580
  rotfe = floatnan(rec[0])
1572
1581
  losses['rotfe'] += rotfe
1573
1582
  losses['total'] += rotfe
@@ -1601,7 +1610,7 @@ class Reader:
1601
1610
  if content[i+1].split() == ['rotf', '----']:
1602
1611
  losses['rotfe'] = sum([floatnan(x) for x in rec])
1603
1612
  losses['total'] += losses['rotfe']
1604
-
1613
+
1605
1614
  if content[i+1].split() == ['Iron', '----']: # external rotor
1606
1615
  losses['rotfe'] = sum([floatnan(x) for x in rec])
1607
1616
  losses['total'] += losses['rotfe']
@@ -643,7 +643,8 @@ def convert(dxfile,
643
643
  params['agndst'] = agndst(params.get('da1'),
644
644
  params.get('da2'),
645
645
  params.get('tot_num_slot'),
646
- params.get('num_poles'), 1)
646
+ params.get('num_poles'),
647
+ params.get('nodedist'))
647
648
 
648
649
  if params['external_rotor']:
649
650
  conv['fsl_magnet'] = outer
@@ -35,6 +35,7 @@ def agndst(da1, da2, Q, p, nodedist=1):
35
35
  num_nodes = [i*lcm for i in range(nmin, nmax) if i*lcm%6==0]
36
36
  dagset = [2*np.pi/p/i for i in num_nodes]
37
37
  i = max(np.argmin(np.abs(np.array(dagset) - np.arctan2(ag, r))), 1)
38
+ # nodedist 0.5, 2, 4, 6
38
39
  nd = min(round(nodedist), i)
39
40
  try:
40
41
  logger.info("Num nodes/p %d Num nodes/slot %g nodedist %g",
@@ -188,7 +189,7 @@ class FslRenderer(object):
188
189
  '-- min_corner = {}, {}'.format(
189
190
  geom.start_min_corner(0),
190
191
  geom.start_min_corner(1)),
191
- '-- max_corner = {}, {}'.format(
192
+ '-- max_corner start = {}, {}'.format(
192
193
  geom.start_max_corner(0),
193
194
  geom.start_max_corner(1)),
194
195
  '\n']
@@ -210,11 +211,12 @@ class FslRenderer(object):
210
211
  'r, phi = c2pr(x0, y0)',
211
212
  'x1, y1 = pr2c(r1, phi)',
212
213
  'x2, y2 = pr2c(r1, {}*math.pi/parts)'.format(slice),
214
+ f'r = {geom.dist_end_max_corner()}',
213
215
  'x3, y3 = pr2c(r, {}*math.pi/parts)'.format(slice),
214
216
  'nc_line(x0, y0, x1, y1, 0)',
215
217
  'nc_circle_m(x1, y1, x2, y2, 0.0, 0.0, 0)',
216
218
  'nc_line(x2, y2, x3, y3, 0)',
217
- 'x0, y0 = pr2c(r1 - hair/2, math.pi/parts)',
219
+ 'x0, y0 = pr2c(r1 - hair/2, math.pi/parts/2)',
218
220
  'create_mesh_se(x0, y0)',
219
221
  '\n',
220
222
  'outer_da_start = {}'.format(
femagtools/fsl.py CHANGED
@@ -106,6 +106,7 @@ class Builder:
106
106
  params['show_plots'] = model.stator[templ].get('plot', False)
107
107
  params['write_fsl'] = True
108
108
  params['airgap'] = -1.0
109
+ params['nodedist'] = model.stator.get('nodedist', 1)
109
110
  pos = 'in' if model.external_rotor else 'out'
110
111
  params['part'] = ('stator', pos)
111
112
  conv = convert(model.stator['dxffile']['name'], **params)
@@ -352,7 +353,7 @@ class Builder:
352
353
  '-- thermal properties in airgap',
353
354
  'ag_cond = 0.063',
354
355
  'thcap = 1007',
355
- 'beta = np.pi*m.npols_gen/m.num_poles + m.zeroangl/180*np.pi',
356
+ 'beta = math.pi*m.npols_gen/m.num_poles + m.zeroangl/180*math.pi',
356
357
  'xai, yai = pr2c((da1+da2)/4, beta)',
357
358
  'def_mat_therm(xai,yai,"cyan",1.19,ag_cond,thcap,1)',
358
359
  'xai, yai = pr2c((da1+da2)/4-ag/4, beta)',
@@ -491,6 +492,11 @@ class Builder:
491
492
  if not hasattr(model, 'stator'):
492
493
  setattr(model, 'stator', {})
493
494
  model.stator['num_slots'] = conv.get('tot_num_slot')
495
+ if model.get('num_agnodes', 0) == 0:
496
+ model.set_value('agndst', conv['agndst']*1e-3)
497
+ logger.info("num poles %d num slots %d outer diameter %.4f m agndst %.4f mm",
498
+ model.poles, model.stator['num_slots'],
499
+ model.outer_diam, model.agndst*1e3)
494
500
  if params['full_model']:
495
501
  model.stator['num_slots_gen'] = model.stator['num_slots']
496
502
  else:
@@ -531,21 +537,6 @@ class Builder:
531
537
  logger.info("create new model '%s'", model.name)
532
538
  if model.is_dxffile():
533
539
  self.prepare_model_with_dxf(model)
534
- if model.get('num_agnodes', 0) == 0:
535
- from femagtools.dxfsl.fslrenderer import agndst
536
- ag = model.get('airgap')
537
- model.set_value(
538
- 'agndst',
539
- agndst(model.get('bore_diam'),
540
- model.get('bore_diam') - 2*ag,
541
- model.stator.get('num_slots'),
542
- model.get('poles'),
543
- model.stator.get('nodedist') or 1.0))
544
-
545
- logger.info(" num poles %d num slots %d outer diameter %.4f m",
546
- model.poles, model.stator['num_slots'],
547
- model.outer_diam)
548
-
549
540
  else:
550
541
  self.prepare_stator(model)
551
542
  if hasattr(model, 'magnet'):
@@ -553,14 +544,17 @@ class Builder:
553
544
  self.prepare_diameter(model)
554
545
  if self.fsl_stator and model.get('num_agnodes', 0) == 0:
555
546
  from femagtools.dxfsl.fslrenderer import agndst
556
- ag = model.get('airgap')
557
- model.set_value(
558
- 'agndst',
559
- agndst(model.get('bore_diam'),
560
- model.get('bore_diam') - 2*ag,
561
- model.stator.get('num_slots'),
562
- model.get('poles'),
563
- model.stator.get('nodedist') or 1.0))
547
+ if model.get('agndst',0):
548
+ pass
549
+ else:
550
+ ag = model.get('airgap')
551
+ model.set_value(
552
+ 'agndst',
553
+ agndst(model.get('bore_diam'),
554
+ model.get('bore_diam') - 2*ag,
555
+ model.stator.get('num_slots'),
556
+ model.get('poles'),
557
+ model.stator.get('nodedist') or 1.0))
564
558
 
565
559
  model.set_num_slots_gen()
566
560
  if hasattr(model, 'magnet'):