femagtools 1.7.3__py3-none-any.whl → 1.7.5__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.3'
5
+ __version__ = '1.7.5'
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,9 +95,9 @@ 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
103
  d['styoke'] = losses[styoke]
@@ -613,6 +613,7 @@ class Reader:
613
613
 
614
614
  def __read_general_machine_data(self, content):
615
615
  mcfiles = []
616
+ slotsides = 1
616
617
  for l in content:
617
618
  try:
618
619
  if l.find('Armature Length') > -1:
@@ -631,8 +632,10 @@ class Reader:
631
632
  self.machine['p_sim'] = int(l.split()[-1])
632
633
  elif l.find('Total Number of Slots') > -1:
633
634
  self.machine['Q'] = int(l.split()[-1])
635
+ elif l.find('Total Number of Slot-Sides') > -1:
636
+ slotsides = int(l.split()[-1])
634
637
  elif l.find('Number of Slot-Sides sim.') > -1:
635
- self.machine['qs_sim'] = int(l.split()[-1])
638
+ self.machine['qs_sim'] = int(l.split()[-1])*self.machine['Q']//slotsides
636
639
  elif l.find('POC-File used in calculation') > -1:
637
640
  self.machine['pocfile'] = l.split(
638
641
  ':')[-1].strip().replace('\\', '\\\\')
@@ -1046,7 +1049,7 @@ class Reader:
1046
1049
  '''
1047
1050
  diff = np.floor(np.abs(np.diff(idList)))
1048
1051
  if idList[-1] == 0 and len(idList) > 2 and \
1049
- not np.all(diff == diff[0]):
1052
+ diff[-1] == 0:
1050
1053
  idList = idList[:-1]
1051
1054
  return idList
1052
1055
 
@@ -1062,7 +1065,8 @@ class Reader:
1062
1065
  m.append([floatnan(x) for x in rec])
1063
1066
 
1064
1067
  m = np.array(m).T
1065
- ncols = np.argmax(np.abs(m[1][1:]-m[1][:-1]))+1
1068
+ d = np.diff(m[1])
1069
+ ncols = (len(d)+1)//(len(d[d < 0])+1)
1066
1070
  if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]: # simple correction
1067
1071
  ncols = 2
1068
1072
  iq = np.reshape(m[1], (-1, ncols))[0]
@@ -1071,7 +1075,8 @@ class Reader:
1071
1075
  ncols = ncols-1
1072
1076
 
1073
1077
  id = np.reshape(m[0], (-1, ncols)).T[0]
1074
- id = self.__removeTrailingZero(id)
1078
+ if id[0] >= 0:
1079
+ id = self.__removeTrailingZero(id)
1075
1080
  nrows = len(id)
1076
1081
  if nrows > 1 and id[nrows-1] < id[nrows-2]:
1077
1082
  nrows = nrows-1
@@ -1096,7 +1101,8 @@ class Reader:
1096
1101
  m.append([floatnan(x) for x in rec])
1097
1102
 
1098
1103
  m = np.array(m).T
1099
- ncols = np.argmax(np.abs(m[1][1:]-m[1][:-1]))+1
1104
+ d = np.diff(m[1])
1105
+ ncols = (len(d)+1)//(len(d[d < 0])+1)
1100
1106
  if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]: # simple correction
1101
1107
  ncols = 2
1102
1108
  iq = np.linspace(np.min(m[1]), np.max(m[1]), ncols)
@@ -1105,7 +1111,8 @@ class Reader:
1105
1111
  ncols = ncols-1
1106
1112
 
1107
1113
  id = np.reshape(m[0], (-1, ncols)).T[0]
1108
- id = self.__removeTrailingZero(id)
1114
+ if id[0] >= 0:
1115
+ id = self.__removeTrailingZero(id)
1109
1116
  nrows = len(id)
1110
1117
  if nrows > 1 and id[nrows-1] < id[nrows-2]:
1111
1118
  nrows = nrows-1
@@ -1168,7 +1175,7 @@ class Reader:
1168
1175
  for name in content[2].split('\t') if name][2:]
1169
1176
  # outer rotor motor
1170
1177
  if 'Iron' in subregs and \
1171
- 'Rotor' in subregs:
1178
+ 'Rotor' in subregs:
1172
1179
  self.external_rotor = True
1173
1180
  logger.info("Stator Subregions: %s", subregs)
1174
1181
  speed = float(content[0].split()[-1])/60.
@@ -1184,7 +1191,11 @@ class Reader:
1184
1191
  if not m:
1185
1192
  return
1186
1193
  m = np.array(m).T
1187
- ncols = np.argmax(np.abs(m[1][1:]-m[1][:-1]))+1
1194
+ d = np.diff(m[1])
1195
+ if self.ldq:
1196
+ ncols = (len(d)+1)//(len(d[d > 0])+1)
1197
+ else:
1198
+ ncols = (len(d)+1)//(len(d[d < 0])+1)
1188
1199
  if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]:
1189
1200
  ncols = 2
1190
1201
  id = np.reshape(m[0], (-1, ncols)).T[0]
@@ -1229,9 +1240,9 @@ class Reader:
1229
1240
  (nrows, ncols)).T.tolist()
1230
1241
  for k, v in zip(cols, m[2:])})
1231
1242
  ls['speed'] = speed
1232
- if self.external_rotor:
1243
+ if self.external_rotor:
1233
1244
  ls.update(losses_mapping_external_rotor(ls))
1234
- else:
1245
+ else:
1235
1246
  ls.update(sttylosses(ls))
1236
1247
  if self.ldq:
1237
1248
  self.ldq['losses'] = ls
@@ -1487,9 +1498,9 @@ class Reader:
1487
1498
  def __read_losses(self, content):
1488
1499
  losses = {}
1489
1500
  i = 0
1490
- # check if external rotor
1501
+ # check if external rotor
1491
1502
  if self.weights[0][1] == 0.0 and \
1492
- self.weights[0][-1] > 0:
1503
+ self.weights[0][-1] > 0:
1493
1504
  self.external_rotor = True
1494
1505
  # find results for angle:
1495
1506
  while True:
@@ -1548,8 +1559,8 @@ class Reader:
1548
1559
  losses['total'] += losses['staza']+losses['stajo']
1549
1560
  elif len(rec) == 1:
1550
1561
  t = l.split(':')[-1].strip()
1551
- if t == 'Iron':
1552
- if self.external_rotor:
1562
+ if t == 'Iron':
1563
+ if self.external_rotor:
1553
1564
  losses['rotfe'] = floatnan(rec[0])
1554
1565
  losses['total'] += losses['rotfe']
1555
1566
  else:
@@ -1561,14 +1572,14 @@ class Reader:
1561
1572
  continue
1562
1573
 
1563
1574
  if _rotloss.search(l):
1564
- if l.find('StZa') > -1:
1575
+ if l.find('StZa') > -1:
1565
1576
  self.external_rotor = True
1566
1577
  rec = self.__findNums(content[i+2])
1567
1578
  if len(rec) == 1:
1568
- if self.external_rotor:
1579
+ if self.external_rotor:
1569
1580
  losses['staza'] = floatnan(rec[0])
1570
1581
  losses['total'] += losses['staza']
1571
- else:
1582
+ else:
1572
1583
  rotfe = floatnan(rec[0])
1573
1584
  losses['rotfe'] += rotfe
1574
1585
  losses['total'] += rotfe
@@ -1602,7 +1613,7 @@ class Reader:
1602
1613
  if content[i+1].split() == ['rotf', '----']:
1603
1614
  losses['rotfe'] = sum([floatnan(x) for x in rec])
1604
1615
  losses['total'] += losses['rotfe']
1605
-
1616
+
1606
1617
  if content[i+1].split() == ['Iron', '----']: # external rotor
1607
1618
  losses['rotfe'] = sum([floatnan(x) for x in rec])
1608
1619
  losses['total'] += losses['rotfe']
femagtools/dxfsl/area.py CHANGED
@@ -84,6 +84,7 @@ class Area(object):
84
84
  self.is_child = False
85
85
  self.areas_inside = {}
86
86
  self.areas_of_group = []
87
+ self.group_is_inside = False
87
88
 
88
89
  def identifier(self):
89
90
  return "{}-{}".format(self.id, self.type)
@@ -189,7 +189,7 @@ class FslRenderer(object):
189
189
  '-- min_corner = {}, {}'.format(
190
190
  geom.start_min_corner(0),
191
191
  geom.start_min_corner(1)),
192
- '-- max_corner = {}, {}'.format(
192
+ '-- max_corner start = {}, {}'.format(
193
193
  geom.start_max_corner(0),
194
194
  geom.start_max_corner(1)),
195
195
  '\n']
@@ -211,11 +211,12 @@ class FslRenderer(object):
211
211
  'r, phi = c2pr(x0, y0)',
212
212
  'x1, y1 = pr2c(r1, phi)',
213
213
  'x2, y2 = pr2c(r1, {}*math.pi/parts)'.format(slice),
214
+ f'r = {geom.dist_end_max_corner()}',
214
215
  'x3, y3 = pr2c(r, {}*math.pi/parts)'.format(slice),
215
216
  'nc_line(x0, y0, x1, y1, 0)',
216
217
  'nc_circle_m(x1, y1, x2, y2, 0.0, 0.0, 0)',
217
218
  'nc_line(x2, y2, x3, y3, 0)',
218
- 'x0, y0 = pr2c(r1 - hair/2, math.pi/parts)',
219
+ 'x0, y0 = pr2c(r1 - hair/2, math.pi/parts/2)',
219
220
  'create_mesh_se(x0, y0)',
220
221
  '\n',
221
222
  'outer_da_start = {}'.format(
femagtools/dxfsl/geom.py CHANGED
@@ -2478,7 +2478,8 @@ class Geometry(object):
2478
2478
  groups_inside = {g.id: g for g in grouplist}
2479
2479
  area.areas_inside = groups_inside
2480
2480
  areas_outside.append(area)
2481
- for g in grouplist:
2481
+ for g in grouplist:
2482
+ g.group_is_inside = True
2482
2483
  alist = groups.get(g.id, [])
2483
2484
  alist.append(area)
2484
2485
  groups[g.id] = alist
@@ -2532,6 +2533,11 @@ class Geometry(object):
2532
2533
  for area in area_list:
2533
2534
  if self.create_aux_lines(area, rightangle, leftangle):
2534
2535
  done = True
2536
+ main_groups = [g for g in self.areagroup_list
2537
+ if not g.group_is_inside]
2538
+ if len(main_groups) > 1:
2539
+ if self.create_outside_aux_lines(main_groups):
2540
+ done = True
2535
2541
  else:
2536
2542
  logger.debug("-> start create_auxiliary_lines")
2537
2543
  self.set_areas_inside_for_all_areas()
@@ -2856,6 +2862,38 @@ class Geometry(object):
2856
2862
  area.get_id())
2857
2863
  return done
2858
2864
 
2865
+ def create_outside_aux_lines(self, grouplist):
2866
+ done = False
2867
+ aux_color = 'blue'
2868
+ aux_linestyle = 'dotted'
2869
+
2870
+ i = 0
2871
+ gaps = []
2872
+ for group in grouplist:
2873
+ i += 1
2874
+ for g in grouplist[i:]:
2875
+ gaps += group.get_lowest_gap_list(g,
2876
+ self.center, self.max_radius,
2877
+ None, None)
2878
+ gaps.sort()
2879
+
2880
+ l = len(grouplist) -1
2881
+ for d, points, token, id in gaps[:l]:
2882
+ logger.info("Token %s", token)
2883
+ line = Line(Element(start=points[0],
2884
+ end=points[1]),
2885
+ color=aux_color,
2886
+ linestyle=aux_linestyle,
2887
+ attr='outside_auxline')
2888
+ n1 = self.find_the_node(line.node1(ndec))
2889
+ n2 = self.find_the_node(line.node2(ndec))
2890
+ if n1 and n2:
2891
+ self.add_element(line,
2892
+ rtol=self.rtol,
2893
+ atol=self.atol)
2894
+ done = True
2895
+ return done
2896
+
2859
2897
  def set_rotor(self):
2860
2898
  self.sym_counterpart = 1
2861
2899
  self.sym_part = 0
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)
@@ -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.dxffile.get('nodedist')))
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,9 +544,9 @@ 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
- if model.get('agndst'):
547
+ if model.get('agndst',0):
557
548
  pass
558
- else:
549
+ else:
559
550
  ag = model.get('airgap')
560
551
  model.set_value(
561
552
  'agndst',