femagtools 1.7.4__py3-none-any.whl → 1.7.6__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.4'
5
+ __version__ = '1.7.6'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2023-2024 Gamma Technology'
femagtools/bch.py CHANGED
@@ -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('\\', '\\\\')
femagtools/dxfsl/area.py CHANGED
@@ -40,6 +40,8 @@ TYPE_MAGNET_OR_IRON = 9
40
40
  TYPE_SHAFT = 10
41
41
  TYPE_MAGNET_RECT_NEAR_AIRGAP = 11
42
42
  TYPE_WINDINGS_OR_AIR = 12
43
+ TYPE_WINDINGS_OR_IRON = 13
44
+ TYPE_FD_WINDINGS = 15
43
45
  TYPE_MAGNET_UNDEFINED = 99
44
46
  TYPE_GROUP = 20
45
47
 
@@ -84,6 +86,7 @@ class Area(object):
84
86
  self.is_child = False
85
87
  self.areas_inside = {}
86
88
  self.areas_of_group = []
89
+ self.group_is_inside = False
87
90
 
88
91
  def identifier(self):
89
92
  return "{}-{}".format(self.id, self.type)
@@ -205,6 +208,8 @@ class Area(object):
205
208
  return 'Iron'
206
209
  if self.type == TYPE_WINDINGS:
207
210
  return 'Windings'
211
+ if self.type == TYPE_FD_WINDINGS:
212
+ return 'Field Windings'
208
213
  if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
209
214
  return 'Magnet'
210
215
  if self.type == TYPE_YOKE:
@@ -220,6 +225,8 @@ class Area(object):
220
225
  return 'Iron'
221
226
  if self.type == TYPE_WINDINGS:
222
227
  return 'Wndg'
228
+ if self.type == TYPE_FD_WINDINGS:
229
+ return 'FD_Wndg'
223
230
  if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
224
231
  return 'Mag'
225
232
  if self.type == TYPE_YOKE:
@@ -235,6 +242,8 @@ class Area(object):
235
242
  return 'cyan'
236
243
  if self.type == TYPE_WINDINGS:
237
244
  return 'green'
245
+ if self.type == TYPE_FD_WINDINGS:
246
+ return 'yellow'
238
247
  if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
239
248
  return 'red'
240
249
  if self.type == TYPE_YOKE:
@@ -250,6 +259,8 @@ class Area(object):
250
259
  return 0.3
251
260
  if self.type == TYPE_WINDINGS:
252
261
  return 1.0
262
+ if self.type == TYPE_FD_WINDINGS:
263
+ return 1.0
253
264
  if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
254
265
  return 1.0
255
266
  if self.type == TYPE_YOKE:
@@ -276,7 +287,9 @@ class Area(object):
276
287
  return self.type == TYPE_IRON
277
288
 
278
289
  def is_winding(self):
279
- return self.type == TYPE_WINDINGS
290
+ return \
291
+ self.type == TYPE_WINDINGS or \
292
+ self.type == TYPE_FD_WINDINGS
280
293
 
281
294
  def is_magnet(self):
282
295
  return self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT
@@ -323,6 +336,17 @@ class Area(object):
323
336
  return True
324
337
  return False
325
338
 
339
+ def minmax_dist_from_center(self, center):
340
+ rmin = 1e20
341
+ rmax = 0
342
+ for n in self.list_of_nodes():
343
+ r = np.linalg.norm(np.array(n)-center)
344
+ if r < rmin:
345
+ rmin = r
346
+ if r > rmax:
347
+ rmax = r
348
+ return rmin, rmax
349
+
326
350
  def minmax_angle_dist_from_center(self, center, dist):
327
351
  circ = Circle(Element(center=center, radius=dist))
328
352
  s = self.area[0]
@@ -1314,11 +1338,89 @@ class Area(object):
1314
1338
  logger.debug("***** air #4\n")
1315
1339
  return 0
1316
1340
 
1317
- def mark_rotor_subregions(self, is_inner, mirrored, alpha,
1318
- center, r_in, r_out,
1319
- startangle,
1320
- endangle):
1321
- logger.debug("mark_rotor_subregions")
1341
+ def mark_EESM_rotor_subregions(self,
1342
+ is_inner,
1343
+ mirrored,
1344
+ alpha,
1345
+ center,
1346
+ r_in,
1347
+ r_out,
1348
+ startangle,
1349
+ endangle):
1350
+ logger.debug("mark_EESM_rotor_subregions")
1351
+
1352
+ alpha = round(alpha, 6)
1353
+
1354
+ if self.is_circle():
1355
+ self.type = TYPE_AIR # air
1356
+ logger.debug(">>> air is a circle")
1357
+ return self.type
1358
+
1359
+ if is_inner:
1360
+ self.close_to_ag = np.isclose(r_out, self.max_dist, rtol=1e-9, atol=0.005)
1361
+ close_to_opposition = greater_equal(r_in * 1.05, self.min_dist)
1362
+ airgap_radius = r_out
1363
+ opposite_radius = r_in
1364
+ airgap_toleranz = -(self.max_dist - self.min_dist) / 50.0 # 2%
1365
+ else:
1366
+ self.close_to_ag = np.isclose(r_in, self.min_dist, rtol=1e-9, atol=0.005)
1367
+ close_to_opposition = greater_equal(self.max_dist * 1.05, r_out)
1368
+ airgap_radius = r_in
1369
+ opposite_radius = r_out
1370
+ airgap_toleranz = (self.max_dist - self.min_dist) / 50.0 # 2%
1371
+
1372
+ self.close_to_startangle = np.isclose(self.min_angle, startangle,
1373
+ 1e-04, 1e-04)
1374
+ self.close_to_endangle = np.isclose(self.max_angle, endangle,
1375
+ 1e-04, 1e-04)
1376
+
1377
+ logger.debug("\n***** mark_EESM_rotor_subregions [{}] *****"
1378
+ .format(self.id))
1379
+ logger.debug(" - close_to_ag : %s", self.close_to_ag)
1380
+ logger.debug(" - close_to_opposition: %s", close_to_opposition)
1381
+ logger.debug(" - min dist : %3.12f", self.min_dist)
1382
+ logger.debug(" - max dist : %3.12f", self.max_dist)
1383
+ logger.debug(" - airgap radius : %3.12f", airgap_radius)
1384
+ logger.debug(" - opposite radius : %3.12f", opposite_radius)
1385
+ logger.debug(" - close_to_startangle: %s", self.close_to_startangle)
1386
+ logger.debug(" - close_to_endangle : %s", self.close_to_endangle)
1387
+ logger.debug(" - alpha : %3.12f", alpha)
1388
+ logger.debug(" - min_angle : %3.12f", self.min_angle)
1389
+ logger.debug(" - max_angle : %3.12f", self.max_angle)
1390
+
1391
+ if self.has_iron_separator():
1392
+ logger.debug("***** iron (has iron separator)\n")
1393
+ self.type = TYPE_IRON # iron
1394
+ return self.type
1395
+
1396
+ if is_inner:
1397
+ # looking for shaft
1398
+ if close_to_opposition and not self.close_to_ag:
1399
+ logger.debug("-- check for shaft")
1400
+ if self.is_shaft_area(center):
1401
+ self.type = TYPE_SHAFT # shaft
1402
+ logger.debug("***** shaft (close to opposition)\n")
1403
+ return self.type
1404
+
1405
+ if close_to_opposition or self.close_to_ag:
1406
+ self.type = TYPE_IRON # iron
1407
+ logger.debug("***** iron (close to opposition)\n")
1408
+ return self.type
1409
+
1410
+ self.type = TYPE_WINDINGS_OR_IRON # windings or iron
1411
+ logger.debug("***** air (somewhere)\n")
1412
+ return self.type
1413
+
1414
+ def mark_PMSM_rotor_subregions(self,
1415
+ is_inner,
1416
+ mirrored,
1417
+ alpha,
1418
+ center,
1419
+ r_in,
1420
+ r_out,
1421
+ startangle,
1422
+ endangle):
1423
+ logger.debug("mark_PMSM_rotor_subregions")
1322
1424
 
1323
1425
  alpha = round(alpha, 6)
1324
1426
 
@@ -1345,7 +1447,7 @@ class Area(object):
1345
1447
  self.close_to_endangle = np.isclose(self.max_angle, endangle,
1346
1448
  1e-04, 1e-04)
1347
1449
 
1348
- logger.debug("\n***** mark_rotor_subregions [{}] *****"
1450
+ logger.debug("\n***** mark_PMSM_rotor_subregions [{}] *****"
1349
1451
  .format(self.id))
1350
1452
  logger.debug(" - close_to_ag : %s", self.close_to_ag)
1351
1453
  logger.debug(" - close_to_opposition: %s", close_to_opposition)
femagtools/dxfsl/conv.py CHANGED
@@ -25,6 +25,16 @@ def main():
25
25
  description='Process DXF file and create a plot or FSL file.')
26
26
  argparser.add_argument('dxfile',
27
27
  help='name of DXF file')
28
+ argparser.add_argument('--PMSM',
29
+ help='Permanent Magnet Synchronous Motor',
30
+ dest='PMSM',
31
+ action="store_true",
32
+ default=False)
33
+ argparser.add_argument('--EESM',
34
+ help='Electric Excited Synchronous Motor',
35
+ dest='EESM',
36
+ action="store_true",
37
+ default=False)
28
38
  argparser.add_argument('--inner',
29
39
  help='name of inner element',
30
40
  dest='inner',
@@ -209,12 +219,17 @@ def main():
209
219
  if args.sym_part not in (3, 4, 6, 8):
210
220
  logger.error("Argument sympart not in (3, 4, 6, 8)")
211
221
  sys.exit(1)
222
+ if args.EESM:
223
+ if args.PMSM:
224
+ logger.error("PMSM or EESM expected (default PMSM)")
225
+ sys.exit(1)
212
226
 
213
227
  if not args.write_fsl:
214
228
  if not (args.show_plots or args.show_areas or args.view):
215
229
  args.write_fsl = True
216
230
 
217
231
  res = convert(args.dxfile, # DXF-Filename
232
+ args.EESM, # motor type EESM or PMSM
218
233
  rtol=args.rtol, # relative pickdist toleranz
219
234
  atol=args.atol, # absolute pickdist toleranz
220
235
  symtol=args.sym_tolerance,
@@ -158,7 +158,7 @@ def symmetry_search(machine,
158
158
  return machine_ok
159
159
 
160
160
 
161
- def build_machine_rotor(machine, inner, mindist, plt, single=False):
161
+ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
162
162
  logger.debug("Begin of build_machine_rotor")
163
163
  if machine.has_windings():
164
164
  logger.debug("do nothing here with windings in rotor")
@@ -170,7 +170,7 @@ def build_machine_rotor(machine, inner, mindist, plt, single=False):
170
170
  machine_temp = machine.undo_mirror()
171
171
  machine_temp.delete_tiny_elements(mindist)
172
172
  machine_temp.geom.set_rotor()
173
- machine_temp.search_rotor_subregions(single=single)
173
+ machine_temp.search_rotor_subregions(EESM, single=single)
174
174
  else:
175
175
  machine_temp = machine
176
176
 
@@ -199,7 +199,7 @@ def build_machine_rotor(machine, inner, mindist, plt, single=False):
199
199
  logger.debug("Auxiliary Lines created: rebuild subregions")
200
200
  rebuild = True
201
201
  if rebuild:
202
- machine_temp.rebuild_subregions(single=single)
202
+ machine_temp.rebuild_subregions(EESM, single=single)
203
203
 
204
204
  machine_temp.geom.recalculate_magnet_orientation()
205
205
  if inner:
@@ -215,7 +215,7 @@ def build_machine_rotor(machine, inner, mindist, plt, single=False):
215
215
  return machine_temp
216
216
 
217
217
 
218
- def build_machine_stator(machine, inner, mindist, plt, single=False):
218
+ def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False):
219
219
  logger.debug("Begin of build_machine_stator")
220
220
  if not machine.geom.is_stator():
221
221
  logger.debug("Rotor with windings")
@@ -230,7 +230,7 @@ def build_machine_stator(machine, inner, mindist, plt, single=False):
230
230
  else:
231
231
  machine_temp = machine
232
232
  if machine_temp.create_auxiliary_lines():
233
- machine_temp.rebuild_subregions(single=single)
233
+ machine_temp.rebuild_subregions(EESM, single=single)
234
234
 
235
235
  if inner:
236
236
  machine_temp.create_inner_corner_areas()
@@ -246,6 +246,7 @@ def build_machine_stator(machine, inner, mindist, plt, single=False):
246
246
 
247
247
 
248
248
  def convert(dxfile,
249
+ EESM=False,
249
250
  rtol=1e-04,
250
251
  atol=1e-03,
251
252
  mindist=0.01,
@@ -505,34 +506,38 @@ def convert(dxfile,
505
506
 
506
507
  machine_inner.sync_with_counterpart(machine_outer)
507
508
 
508
- machine_inner.search_subregions()
509
- machine_outer.search_subregions()
509
+ machine_inner.search_subregions(EESM)
510
+ machine_outer.search_subregions(EESM)
510
511
 
511
512
  # Inner mirrored rotor
512
513
  if machine_inner.geom.is_rotor():
513
514
  machine_inner = build_machine_rotor(machine_inner,
514
515
  True, # is inner
515
516
  mindist,
516
- p)
517
+ p,
518
+ EESM=EESM)
517
519
 
518
520
  # Outer mirrored rotor
519
521
  if machine_outer.geom.is_rotor():
520
522
  machine_outer = build_machine_rotor(machine_outer,
521
523
  False, # is outer
522
524
  mindist,
523
- p)
525
+ p,
526
+ EESM=EESM)
524
527
 
525
528
  if machine_inner.geom.is_stator() or machine_inner.has_windings():
526
529
  machine_inner = build_machine_stator(machine_inner,
527
530
  True,
528
531
  mindist,
529
- p)
532
+ p,
533
+ EESM=EESM)
530
534
 
531
535
  if machine_outer.geom.is_stator() or machine_outer.has_windings():
532
536
  machine_outer = build_machine_stator(machine_outer,
533
537
  False,
534
538
  mindist,
535
- p)
539
+ p,
540
+ EESM=EESM)
536
541
  machine_inner.sync_with_counterpart(machine_outer)
537
542
 
538
543
  machine_inner.search_critical_elements(mindist)
@@ -707,20 +712,30 @@ def convert(dxfile,
707
712
  machine.geom.set_stator()
708
713
  machine.set_inner_or_outer(part[1])
709
714
  machine.search_stator_subregions(single=True)
710
- machine = build_machine_stator(machine, inner, mindist, p, single=True)
715
+ machine = build_machine_stator(machine,
716
+ inner,
717
+ mindist,
718
+ p,
719
+ EESM=EESM,
720
+ single=True)
711
721
 
712
722
  params = create_femag_parameters_stator(machine,
713
723
  part[1])
714
724
  else:
715
725
  machine.geom.set_rotor()
716
726
  machine.set_inner_or_outer(part[1])
717
- machine.search_rotor_subregions(single=True)
718
- machine = build_machine_rotor(machine, inner, mindist, p, single=True)
727
+ machine.search_rotor_subregions(EESM, single=True)
728
+ machine = build_machine_rotor(machine,
729
+ inner,
730
+ mindist,
731
+ p,
732
+ EESM=EESM,
733
+ single=True)
719
734
 
720
735
  params = create_femag_parameters_rotor(machine,
721
736
  part[1])
722
737
  else:
723
- machine.search_subregions(single=True)
738
+ machine.search_subregions(EESM, single=True)
724
739
 
725
740
  machine.create_inner_corner_areas()
726
741
 
@@ -254,6 +254,9 @@ class FslRenderer(object):
254
254
  if area.type not in subregions:
255
255
  subregions[area.type] = 1
256
256
  num_windings += 1
257
+ rmin, rmax = area.minmax_dist_from_center((0,0))
258
+ self.content.append(
259
+ f'rcoil_{num_windings} = {rmin}, {rmax}')
257
260
  self.content.append('m.xcoil_{}, m.ycoil_{} = x0, y0'.
258
261
  format(num_windings, num_windings))
259
262
 
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
@@ -3002,11 +3040,20 @@ class Geometry(object):
3002
3040
  for e in elist:
3003
3041
  e.init_attributes('lightblue', 'no_fsl')
3004
3042
 
3005
- def search_subregions(self, startangle, endangle, single=False):
3043
+ def search_subregions(self, startangle, endangle, EESM, single=False):
3006
3044
  if self.is_stator():
3007
- self.search_stator_subregions(startangle, endangle, single=single)
3045
+ self.search_stator_subregions(startangle,
3046
+ endangle,
3047
+ single=single)
3008
3048
  elif self.is_rotor():
3009
- self.search_rotor_subregions(startangle, endangle, single=single)
3049
+ if EESM:
3050
+ self.search_EESM_rotor_subregions(startangle,
3051
+ endangle,
3052
+ single=single)
3053
+ else:
3054
+ self.search_PMSM_rotor_subregions(startangle,
3055
+ endangle,
3056
+ single=single)
3010
3057
  else:
3011
3058
  logger.warning("no stator or rotor assigned")
3012
3059
  self.search_unknown_subregions()
@@ -3224,25 +3271,88 @@ class Geometry(object):
3224
3271
  self.check_shaft_area(shaft_areas[0])
3225
3272
  logger.debug("End of search_stator_subregions")
3226
3273
 
3227
- def search_rotor_subregions(self,
3228
- startangle,
3229
- endangle,
3230
- single=False):
3231
- logger.debug("Begin of search_rotor_subregions")
3274
+ def search_EESM_rotor_subregions(self,
3275
+ startangle,
3276
+ endangle,
3277
+ single=False):
3278
+ logger.debug("Begin of search_EESM_rotor_subregions")
3279
+
3280
+ if self.alfa == 0.0:
3281
+ self.alfa = np.pi * 2.0
3282
+
3283
+ types = {}
3284
+ for area in self.list_of_areas():
3285
+ t = area.mark_EESM_rotor_subregions(self.is_inner,
3286
+ self.is_mirrored(),
3287
+ self.alfa,
3288
+ self.center,
3289
+ self.min_radius,
3290
+ self.max_radius,
3291
+ startangle,
3292
+ endangle)
3293
+ if t in types:
3294
+ types[t] += 1
3295
+ else:
3296
+ types[t] = 1
3297
+
3298
+ windings = [a for a in self.list_of_areas()
3299
+ if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
3300
+
3301
+ if self.is_mirrored():
3302
+ [a.set_type(AREA.TYPE_IRON) for a in windings
3303
+ if a.close_to_endangle]
3304
+ wlist = [(a.max_angle, a) for a in self.list_of_areas()
3305
+ if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
3306
+ if wlist:
3307
+ wlist.sort(reverse=True)
3308
+ a, w = wlist[0]
3309
+ w.set_type(AREA.TYPE_FD_WINDINGS)
3310
+ else:
3311
+ midangle = middle_angle(startangle, endangle)
3312
+ [a.set_type(AREA.TYPE_IRON) for a in windings
3313
+ if a.max_angle > midangle and a.min_angle < midangle]
3314
+ windings = [a for a in self.list_of_areas()
3315
+ if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
3316
+ if len(windings) > 1:
3317
+ wlist = []
3318
+ for w in windings:
3319
+ if w.max_angle < midangle:
3320
+ angle = alpha_angle(w.max_angle, midangle)
3321
+ else:
3322
+ angle = alpha_angle(midangle, w.min_angle)
3323
+ wlist.append((angle, w))
3324
+ wlist.sort()
3325
+ a1, w1 = wlist[0]
3326
+ a2, w2 = wlist[1]
3327
+ if np.isclose(a1, a2):
3328
+ w1.set_type(AREA.TYPE_FD_WINDINGS)
3329
+ w2.set_type(AREA.TYPE_FD_WINDINGS)
3330
+
3331
+ # all remaining areas are in iron
3332
+ [a.set_type(AREA.TYPE_IRON) for a in self.list_of_areas()
3333
+ if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
3334
+
3335
+ logger.debug("End of search_EESM_rotor_subregions")
3336
+
3337
+ def search_PMSM_rotor_subregions(self,
3338
+ startangle,
3339
+ endangle,
3340
+ single=False):
3341
+ logger.debug("Begin of search_PMSM_rotor_subregions")
3232
3342
 
3233
3343
  if self.alfa == 0.0:
3234
3344
  self.alfa = np.pi * 2.0
3235
3345
 
3236
3346
  types = {}
3237
3347
  for area in self.list_of_areas():
3238
- t = area.mark_rotor_subregions(self.is_inner,
3239
- self.is_mirrored(),
3240
- self.alfa,
3241
- self.center,
3242
- self.min_radius,
3243
- self.max_radius,
3244
- startangle,
3245
- endangle)
3348
+ t = area.mark_PMSM_rotor_subregions(self.is_inner,
3349
+ self.is_mirrored(),
3350
+ self.alfa,
3351
+ self.center,
3352
+ self.min_radius,
3353
+ self.max_radius,
3354
+ startangle,
3355
+ endangle)
3246
3356
  if t in types:
3247
3357
  types[t] += 1
3248
3358
  else:
@@ -3370,7 +3480,7 @@ class Geometry(object):
3370
3480
  self.search_stator_subregions(startangle, endangle, single=single)
3371
3481
  return
3372
3482
 
3373
- logger.debug("end of search_rotor_subregions")
3483
+ logger.debug("end of search_PMSM_rotor_subregions")
3374
3484
 
3375
3485
  def recalculate_magnet_orientation(self):
3376
3486
  logger.debug("begin of recalculate_magnet_orientation")
@@ -1046,21 +1046,36 @@ class Machine(object):
1046
1046
  cp_machine.geom.sym_counterpart = self.get_symmetry_part()
1047
1047
  cp_machine.geom.sym_part = cp_machine.get_symmetry_part()
1048
1048
 
1049
- def search_subregions(self, single=False):
1049
+ def search_subregions(self, EESM, single=False):
1050
1050
  logger.debug("Search subregions")
1051
- self.geom.search_subregions(self.startangle, self.endangle, single=single)
1052
-
1053
- def search_rotor_subregions(self, single=False):
1054
- self.geom.search_rotor_subregions(self.startangle, self.endangle, single=single)
1051
+ self.geom.search_subregions(self.startangle,
1052
+ self.endangle,
1053
+ EESM,
1054
+ single=single)
1055
+
1056
+ def search_rotor_subregions(self, EESM, single=False):
1057
+ if EESM:
1058
+ self.geom.search_EESM_rotor_subregions(self.startangle,
1059
+ self.endangle,
1060
+ single=single)
1061
+ else:
1062
+ self.geom.search_PMSM_rotor_subregions(self.startangle,
1063
+ self.endangle,
1064
+ single=single)
1055
1065
 
1056
1066
  def search_stator_subregions(self, single=False):
1057
- self.geom.search_stator_subregions(self.startangle, self.endangle, single=single)
1067
+ self.geom.search_stator_subregions(self.startangle,
1068
+ self.endangle,
1069
+ single=single)
1058
1070
 
1059
- def rebuild_subregions(self, single=False):
1071
+ def rebuild_subregions(self, EESM, single=False):
1060
1072
  logger.debug("Rebuild subregions")
1061
1073
  self.geom.set_edge_attributes()
1062
1074
  self.geom.area_list = []
1063
- self.geom.search_subregions(self.startangle, self.endangle, single=single)
1075
+ self.geom.search_subregions(self.startangle,
1076
+ self.endangle,
1077
+ EESM,
1078
+ single=single)
1064
1079
 
1065
1080
  def has_windings(self):
1066
1081
  return self.geom.has_windings
@@ -1170,7 +1185,9 @@ class Machine(object):
1170
1185
  self.geom.area_list = []
1171
1186
  logger.debug("create subregions again")
1172
1187
  self.geom.create_list_of_areas()
1173
- self.geom.search_subregions(self.startangle, self.endangle)
1188
+ self.geom.search_subregions(self.startangle,
1189
+ self.endangle,
1190
+ False)
1174
1191
 
1175
1192
  logger.debug("end create_mirror_lines_outside_windings")
1176
1193
 
femagtools/fsl.py CHANGED
@@ -768,7 +768,10 @@ class Builder:
768
768
 
769
769
  return (fslmodel + self.create_analysis(sim) +
770
770
  ['save_model("close")'])
771
-
771
+
772
+ def create_detailed_wire(self, params, templ):
773
+ return self.__render(params, templ)
774
+
772
775
  def __render(self, model, templ, stator=False, magnet=False):
773
776
  if templ.split('.')[-1] in ('fsl', 'mako'):
774
777
  try:
femagtools/machine/pm.py CHANGED
@@ -5,7 +5,7 @@ import logging
5
5
  import warnings
6
6
  import numpy as np
7
7
  import numpy.linalg as la
8
- from .utils import iqd, betai1, skin_resistance, dqparident, KTH, K
8
+ from .utils import iqd, betai1, skin_resistance, dqparident, KTH, K, T
9
9
  import scipy.optimize as so
10
10
  import scipy.interpolate as ip
11
11
  import scipy.integrate as ig
@@ -14,6 +14,38 @@ from functools import partial
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
16
 
17
+ def find_peaks_and_valleys(t, iabc, tshort):
18
+ """ return peaks and valleys of phase current with maximum amplitude
19
+ """
20
+ iph = iabc[np.argmax([np.max(np.abs(iph))
21
+ for iph in iabc])]
22
+ ts = t[t>tshort]
23
+ Z = iph[t>tshort]
24
+ peaks = (np.diff(np.sign(np.diff(Z))) < 0).nonzero()[0] + 1
25
+ if len(peaks>0):
26
+ p = {'ip': Z[peaks].tolist(), 'tp': ts[peaks].tolist()}
27
+ else:
28
+ p = {'ip': [], 'tp': []}
29
+ valleys = (np.diff(np.sign(np.diff(Z))) > 0).nonzero()[0] + 1
30
+ if len(valleys>0):
31
+ v = {'iv': Z[valleys].tolist(), 'tv': ts[valleys].tolist()}
32
+ else:
33
+ v = {'iv': [], 'tv': []}
34
+ try:
35
+ cs = ip.CubicSpline(ts[peaks], Z[peaks])
36
+ p.update({'i': cs(ts).tolist(), 't': ts.tolist()})
37
+ except ValueError as e:
38
+ logger.warning("no peaks in current: %d",
39
+ len(peaks))
40
+ try:
41
+ cs = ip.CubicSpline(ts[valleys], Z[valleys])
42
+ v.update({'i': cs(ts).tolist(), 't': ts.tolist()})
43
+ except ValueError as e:
44
+ logger.warning("no valleys in current: %d",
45
+ len(valleys))
46
+ return p, v
47
+
48
+
17
49
  def parident(workdir, engine, temp, machine,
18
50
  magnetizingCurves, magnetMat, condMat,
19
51
  **kwargs):
@@ -1487,68 +1519,184 @@ class PmRelMachinePsidq(PmRelMachine):
1487
1519
  def betai1_plmag(self, beta, i1, f1):
1488
1520
  return self.iqd_plmag(*iqd(beta, i1), f1)
1489
1521
 
1522
+ def ldlqpsim(self):
1523
+ def ext_array(id, iq, a):
1524
+ """extend array a if current is 0 at edge
1525
+ id: list of n id values
1526
+ iq: list of m iq values
1527
+ a: nxm array to extend"""
1528
+ if id[0] == 0:
1529
+ y = np.array(a)[:, 1].reshape((-1, 1))
1530
+ m = np.hstack((y, a))
1531
+ elif id[-1] == 0:
1532
+ y = np.array(a)[:, -2].reshape((-1, 1))
1533
+ m = np.hstack((a, y))
1534
+ else:
1535
+ m = np.array(a)
1536
+
1537
+ if iq[0] == 0:
1538
+ return np.concatenate(([m[1]], m))
1539
+ elif iq[-1] == 0:
1540
+ return np.concatenate((m, [m[-2]]))
1541
+
1542
+ return m
1543
+
1544
+ idn = np.append(self.id, -self.id[-2])
1545
+ iqz = np.where(self.iq == 0.)[0][0]
1546
+ if iqz in {0, len(self.iq)-1}:
1547
+ iqn = np.insert(self.iq, 0, -self.iq[1])
1548
+ elif iqz == len(self.iq)-1:
1549
+ iqn = np.append(self.iq, -self.iq[iqz-1])
1550
+ else:
1551
+ iqn = np.array(self.iq)
1552
+ psid2 = ext_array(self.id, self.iq, self.psid)
1553
+ psiq2 = ext_array(self.id, self.iq, self.psiq)
1554
+
1555
+ # create n x m matrix of currents
1556
+ id = np.ones(psid2.shape) * idn
1557
+ iq = (np.ones(psid2.shape).T * iqn).T
1558
+
1559
+ # calculate ec model parameters
1560
+ psim = (np.ones(psid2.shape).T * psid2[id == 0.]).T
1561
+ nz = np.any(id != 0., axis=0)
1562
+ ld = ((psid2-psim)[:, nz])/id[:, nz]
1563
+ nz = np.any(iq != 0., axis=1)
1564
+ lq = (psiq2[nz, :])/iq[nz, :]
1565
+
1566
+ # create interpolation functions
1567
+ return (ip.RectBivariateSpline(iq[:, 0], id[0][id[0] != 0], ld),
1568
+ ip.RectBivariateSpline(iq[:, 0][iq[:, 0] != 0], id[0], lq),
1569
+ ip.RectBivariateSpline(iq[:, 0], id[0], psim))
1570
+
1490
1571
 
1491
1572
  ### EXPERIMENTAL
1492
1573
 
1493
1574
  def transient(self, u1, tload, speed,
1494
1575
  fault_type=3, # 'LLL', 'LL', 'LG',
1495
- tend=0.1, nsamples=200):
1496
-
1497
- tshort = 0
1576
+ tshort=0, tend=0.1, nsamples=200):
1577
+ ns = round(tshort/tend*nsamples), round((tend-tshort)/tend*nsamples)
1498
1578
  w1 = 2*np.pi*self.p*speed
1579
+ i0 = self.iqd_torque(tload)
1499
1580
  res = so.minimize(
1500
- lambda iqd: np.linalg.norm(iqd), self.io, method='SLSQP',
1581
+ np.linalg.norm, i0, method='SLSQP',
1501
1582
  constraints=(
1502
- {'type': 'eq',
1583
+ {'type': 'ineq',
1503
1584
  'fun': lambda iqd: self.tmech_iqd(*iqd, speed) - tload},
1504
1585
  {'type': 'ineq',
1505
1586
  'fun': lambda iqd: np.sqrt(2)*u1
1506
1587
  - la.norm(self.uqd(w1, *iqd))}))
1507
1588
  iqx, idx = res.x
1508
1589
  uq0, ud0 = self.uqd(w1, iqx, idx)
1590
+ psid = ip.RectBivariateSpline(self.iq, self.id, self.psid, kx=3, ky=3)
1591
+ psiq = ip.RectBivariateSpline(self.iq, self.id, self.psiq, kx=3, ky=3)
1509
1592
  logger.info("transient: Torque %f Nm, Speed %f rpm, Curr %f A",
1510
1593
  tload, speed*60, betai1(iqx, idx)[1])
1594
+ #_ld, _lq, _psim = self.ldlqpsim()
1595
+ #Ld = _ld(iqx, idx)[0, 0]
1596
+ #Lq = _lq(iqx, idx)[0, 0]
1597
+ #psim = _psim(iqx, idx)[0, 0]
1598
+ #logger.info("idx %f iqx %f, Ld %f, Lq %f, psim %f",
1599
+ # idx, iqx, Ld, Lq, psim)
1511
1600
  if fault_type == 3: # 3 phase short circuit
1512
- USC = lambda t: np.zeros(2)
1601
+ Y0 = iqx, idx
1602
+ def U(t):
1603
+ return (uq0, ud0) if t < tshort else (0, 0)
1604
+ def didt(t, iqd):
1605
+ uq, ud = U(t)
1606
+ ldd = psid(*iqd, dx=0, dy=1)[0,0]
1607
+ lqq = psiq(*iqd, dx=1, dy=0)[0,0]
1608
+ ldq = psid(*iqd, dx=1, dy=0)[0,0]
1609
+ lqd = psiq(*iqd, dx=0, dy=1)[0,0]
1610
+ psi = psid(*iqd)[0,0], psiq(*iqd)[0,0]
1611
+ return [
1612
+ (-ldd*psi[0]*w1 + ldd*(uq-self.r1*iqd[0])
1613
+ - lqd*psi[1]*w1 - lqd*(ud-self.r1*iqd[1]))/(ldd*lqq - ldq*lqd),
1614
+ (ldq*psi[0]*w1 - ldq*(uq-self.r1*iqd[0])
1615
+ + lqq*psi[1]*w1 + lqq*(ud-self.r1*iqd[1]))/(ldd*lqq - ldq*lqd)]
1616
+ #def didtl(t, iqd):
1617
+ # lqd = lq(*iqd)[0,0], ld(*iqd)[0,0]
1618
+ # return [
1619
+ # (uq-r1*iqd[0] -w1 * ld*iqd[1] - w1*psim(*iqd)[0,0])/lq,
1620
+ # (ud-r1*iqd[1] +w1 * lq*iqd[0])/ld]
1513
1621
  else: # 2 phase short circuit
1514
- #ustat = np.array([K(w1*x).dot((uq, ud)) for x in t])
1515
- USC = lambda t: np.array([
1516
- uq0/2*(1+np.cos(2*w1*t)),
1517
- uq0/2*np.sin(2*w1*t)])
1518
- U = lambda t: (uq0, ud0) if t < tshort else USC(t)
1519
-
1520
- psid = ip.RectBivariateSpline(self.iq, self.id, self.psid, kx=3, ky=3)
1521
- psiq = ip.RectBivariateSpline(self.iq, self.id, self.psiq, kx=3, ky=3)
1522
- #ld = ip.RectBivariateSpline(iq, id, dqpars['psidq'][0]['ld'], kx=3, ky=3)
1523
- #lq = ip.RectBivariateSpline(iq, id, dqpars['psidq'][0]['lq'], kx=3, ky=3)
1524
- #psim = ip.RectBivariateSpline(iq, id, dqpars['psidq'][0]['psim'], kx=3, ky=3)
1525
- #def didtl(t, iqd):
1526
- # lqd = lq(*iqd)[0,0], ld(*iqd)[0,0]
1527
- # return [
1528
- # (uq-r1*iqd[0] -w1 * lqd[1]*iqd[1] - w1*psim(*iqd)[0,0])/lqd[0],
1529
- # (ud-r1*iqd[1] +w1*lqd[0]*iqd[0])/lqd[1]]
1530
-
1531
- def didt(t, iqd):
1532
- uq, ud = U(t)
1533
- ldd = psid(*iqd, dx=0, dy=1)[0,0]
1534
- lqq = psiq(*iqd, dx=1, dy=0)[0,0]
1535
- ldq = psid(*iqd, dx=1, dy=0)[0,0]
1536
- lqd = psiq(*iqd, dx=0, dy=1)[0,0]
1537
- psi = psid(*iqd)[0,0], psiq(*iqd)[0,0]
1538
- return [
1539
- (-ldd*psi[0]*w1 + ldd*(uq-self.r1*iqd[0])
1540
- - lqd*psi[1]*w1 - lqd*(ud-self.r1*iqd[1]))/(ldd*lqq - ldq*lqd),
1541
- (ldq*psi[0]*w1 - ldq*(uq-self.r1*iqd[0])
1542
- + lqq*psi[1]*w1 + lqq*(ud-self.r1*iqd[1]))/(ldd*lqq - ldq*lqd)]
1543
-
1544
- t = np.linspace(0, tend, nsamples)
1545
- Y0 = iqx, idx
1622
+ _ld, _lq, _psim = self.ldlqpsim()
1623
+ Ld = _ld(iqx, idx)[0, 0]
1624
+ Lq = _lq(iqx, idx)[0, 0]
1625
+ psim = _psim(iqx, idx)[0, 0]
1626
+ Y0 = (0,)
1627
+ def didt(t, i):
1628
+ gamma = w1*t
1629
+ iqd = [2/3*i*(-np.sin(gamma) + np.sin(gamma+2*np.pi/3)),
1630
+ 2/3*i*(np.cos(gamma) + np.cos(gamma+2*np.pi/3))]
1631
+ ldd = psid(*iqd, dx=0, dy=1)[0,0]
1632
+ lqq = psiq(*iqd, dx=1, dy=0)[0,0]
1633
+ ldq = psid(*iqd, dx=1, dy=0)[0,0]
1634
+ lqd = psiq(*iqd, dx=0, dy=1)[0,0]
1635
+ psi = psid(*iqd)[0, 0], psiq(*iqd)[0, 0]
1636
+ A = ((ldd-lqq)*np.cos(2*gamma + np.pi/3)
1637
+ - (ldq+lqd)*np.sin(2*gamma + np.pi/3) + lqq + ldd)
1638
+ B = 2/3*w1*((ldd-lqq)*np.sin(2*gamma + np.pi/3)
1639
+ + (ldq+lqd)*np.cos(2*gamma + np.pi/3)
1640
+ + ldq - lqd) + 2*self.r1
1641
+ C = np.sqrt(3)*w1*(psi[0]*np.sin(gamma + np.pi/6)
1642
+ + psi[1]*np.cos(gamma + np.pi/6))
1643
+ return -(B*i + C)/A
1644
+
1645
+ #def didt2(t, i):
1646
+ # gamma = w1*t
1647
+ # idy, iqy = T(gamma).dot([i[0], -i[0], 0])
1648
+ # ua - ub = 0; ia = -ib; ic = 0
1649
+ # B = np.sqrt(3)*psim*np.cos(gamma + np.pi/6)
1650
+ # A = 2*Ld*np.cos(gamma + np.pi/6)**2 + 2*Lq*np.sin(gamma + np.pi/6)**2
1651
+ # dAdt = 4*w1*np.cos(gamma+np.pi/6)*np.sin(gamma+np.pi/6)*(Ld - Lq)
1652
+ # dBdt = np.sqrt(3)*w1*psim*np.sin(gamma+np.pi/6)
1653
+
1654
+ # return -(i*dAdt + dBdt + 2*self.r1*i)/A
1655
+
1656
+ t = np.linspace(tshort, tend, ns[1])
1546
1657
  sol = ig.solve_ivp(didt, (t[0], t[-1]), Y0, dense_output=True)
1547
1658
  y = sol.sol(t).T
1548
1659
 
1660
+ t = np.linspace(0, tend, nsamples)
1661
+ if fault_type == 3: # 3 phase short circuit
1662
+ if ns[0] > 0:
1663
+ iqd = np.vstack(
1664
+ (np.ones((ns[0], 2)) * (iqx, idx), y))
1665
+ else:
1666
+ iqd = y
1667
+ iabc = np.array([K(w1*x[0]).dot((x[1][1], x[1][0]))
1668
+ for x in zip(t, iqd)]).T
1669
+ peaks, valleys = find_peaks_and_valleys(t, iabc, tshort)
1670
+
1671
+ #iqx, idx = iqd[-1, 0], iqd[-1, 1],
1672
+ #Ld = _ld(iqx, idx)[0, 0]
1673
+ #Lq = _lq(iqx, idx)[0, 0]
1674
+ #psim = _psim(iqx, idx)[0, 0]
1675
+ #logger.info("idx %f iqx %f, Ld %f, Lq %f, psim %f",
1676
+ # idx, iqx, Ld, Lq, psim)
1677
+ return {
1678
+ 't': t.tolist(),
1679
+ 'iq': iqd[:,0], 'id': iqd[:,1],
1680
+ 'istat': iabc.tolist(),
1681
+ 'peaks': peaks,
1682
+ 'valleys': valleys,
1683
+ 'torque': [self.torque_iqd(*x) for x in iqd]}
1684
+ if ns[0] > 0:
1685
+ iabc = np.hstack(
1686
+ (np.array(
1687
+ [K(w1*t).dot((idx, iqx))
1688
+ for t in np.linspace(0, tshort, ns[0])]).T,
1689
+ [y[:, 0], (-y)[:, 0], np.zeros(ns[1])]))
1690
+ else:
1691
+ iabc = np.array(
1692
+ [y[:, 0], (-y)[:, 0], np.zeros(len(t))])
1693
+ peaks, valleys = find_peaks_and_valleys(t, iabc, tshort)
1694
+ idq = np.array([T(w1*x[0]).dot(x[1])
1695
+ for x in zip(t, iabc.T)]).T
1549
1696
  return {
1550
1697
  't': t.tolist(),
1551
- 'iq': y[:,0], 'id': y[:,1],
1552
- 'istat': np.array([K(w1*x[0]).dot((x[1][1], x[1][0]))
1553
- for x in zip(t, y)]).T.tolist(),
1554
- 'torque': [self.torque_iqd(*iqd) for iqd in y]}
1698
+ 'iq': idq[1], 'id': idq[0],
1699
+ 'istat': iabc.tolist(),
1700
+ 'peaks': peaks,
1701
+ 'valleys': valleys,
1702
+ 'torque': self.torque_iqd(idq[1], idq[0])}
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
14
14
 
15
15
  def K(d):
16
16
  """space phasor transformation matrix
17
- (Inverse Park Transformation) T-1 * dq
17
+ (Inverse Park Transformation) T-1 * dq --> abc
18
18
  arguments:
19
19
  d: rotation angle
20
20
 
@@ -28,7 +28,7 @@ def K(d):
28
28
 
29
29
  def T(d):
30
30
  """space phasor transformation matrix
31
- (Park Transformation) T * abc
31
+ (Park Transformation) T * abc --> dq
32
32
  arguments:
33
33
  d: rotation angle
34
34
 
femagtools/plot/bch.py CHANGED
@@ -508,19 +508,33 @@ def transientsc(bch, title=''):
508
508
  row = 1
509
509
  plt.subplot(rows, cols, row)
510
510
  ax = plt.gca()
511
- ax.set_title('Currents / A')
512
511
  ax.grid(True)
513
- for i in ('ia', 'ib', 'ic'):
514
- ax.plot(bch.scData['time'], bch.scData[i], label=i)
512
+ istat = np.array([bch.scData[i]
513
+ for i in ('ia', 'ib', 'ic')])
514
+ if np.max(istat) > 4000:
515
+ istat *= 1e-3
516
+ ax.set_title('Currents / kA')
517
+ else:
518
+ ax.set_title('Currents / A')
519
+
520
+ for i, iph in zip(('ia', 'ib', 'ic'), istat):
521
+ ax.plot(bch.scData['time'], iph, label=i)
515
522
  ax.set_xlabel('Time / s')
516
523
  ax.legend()
517
524
 
518
525
  row = 2
519
526
  plt.subplot(rows, cols, row)
520
527
  ax = plt.gca()
521
- ax.set_title('Torque / Nm')
528
+ scale = 1
529
+ torque = np.array(bch.scData['torque'])
530
+ if np.max(torque) > 4000:
531
+ torque *= 1e-3
532
+ ax.set_title('Torque / kNm')
533
+ else:
534
+ ax.set_title('Torque / Nm')
535
+
522
536
  ax.grid(True)
523
- ax.plot(bch.scData['time'], bch.scData['torque'])
537
+ ax.plot(bch.scData['time'], torque)
524
538
  ax.set_xlabel('Time / s')
525
539
 
526
540
  fig.tight_layout(h_pad=2)
@@ -14,13 +14,22 @@ if not airgap_created then
14
14
  end
15
15
  % if hasattr(model, 'bore_diam'):
16
16
  r1 = m.fc_radius - ag/6
17
+ if(m.npols_gen == m.num_poles) then
18
+ alfa = alfa / 2
19
+ end
17
20
  x1, y1 = pr2c(r1, alfa)
18
21
  n = math.floor(m.fc_radius*alfa/agndst + 1.5)
19
22
  nc_circle_m(r1, 0, x1, y1, 0.0, 0.0, n)
23
+ if(m.npols_gen == m.num_poles) then
24
+ nc_circle_m(x1, y1, r1, 0, 0.0, 0.0, n)
25
+ end
20
26
 
21
27
  r2 = m.fc_radius + ag/6
22
28
  x2, y2 = pr2c(r2, alfa)
23
29
  nc_circle_m(r2, 0, x2, y2, 0.0, 0.0, n)
30
+ if(m.npols_gen == m.num_poles) then
31
+ nc_circle_m(x2, y2, r2, 0, 0.0, 0.0, n)
32
+ end
24
33
 
25
34
  if inner_da_start == nil then
26
35
  inner_da_start = da2/2
@@ -34,6 +34,9 @@ m.slot_top_sh = ${model['slot_top_sh']}
34
34
  m.zeroangl = ${model.get('zeroangle',0)}
35
35
  m.rlength = ${model.get('rlength',1)*100}
36
36
 
37
+ % if model.get('ac_loss', False):
38
+ m.ac_loss = ${model.get('ac_loss', 3)}
39
+ % endif
37
40
  m.mcvkey_yoke = mcvkey_yoke
38
41
 
39
42
  pre_models("STATOR_3")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: femagtools
3
- Version: 1.7.4
3
+ Version: 1.7.6
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,9 +1,9 @@
1
- femagtools/__init__.py,sha256=LQSh6OjWbECaFlDSZXzy-njc7_TUylPuMfvbQVJYH9I,1600
1
+ femagtools/__init__.py,sha256=bsP3-dUn57w5F0J2342CXVQfsk2pVYuVby-g3MuoFjM,1600
2
2
  femagtools/airgap.py,sha256=hELJXe52yUw82JwZ1tGUXUtRhMG2_WSUBVeGkTZSAM8,1900
3
3
  femagtools/amazon.py,sha256=O1ICuv21XDAJi1qK1Sigs2TdS6hDZP19OzvmE2t76wU,12069
4
4
  femagtools/amela.py,sha256=pHjfXzpANI-7oz8MtrqNcyDZ6PxVM91vCJuvYhHy1rk,13891
5
5
  femagtools/asm.py,sha256=CiL0KWaF4P7O6-VwmGLdva_icwmPrPiI-TFQ19XYTKk,7660
6
- femagtools/bch.py,sha256=aWTOQ8Hq2ygLPQpf5k9W0nWUPK0UXe0YewArrPI7IBk,73550
6
+ femagtools/bch.py,sha256=FYpQsbCaJB6GJHwUto4aCq94Yz1DtYAbaj7l-gGjmY4,73716
7
7
  femagtools/bchxml.py,sha256=KrRjAdrUPZXmiWvonu9HhpG_NvImMBpiXWTL4iSr4kE,3142
8
8
  femagtools/condor.py,sha256=J8z9iBdvrGu3I1eFNoyKV8AXzRoTEPGLSak6cXUQxAM,10766
9
9
  femagtools/conductor.py,sha256=rXO7c7Qh_s7JpgILmLd4IbG64vP6Eh143YF9u25Mdwg,1076
@@ -17,7 +17,7 @@ femagtools/ecloss.py,sha256=gaZ8JmlFVoP6IYe79YXPXvZSULm8IZr6bPBdKuyKaIo,12832
17
17
  femagtools/erg.py,sha256=IXKq76P9qLt_ssNOP78v8Qizk3J2Zg80yaKDSjzwoJE,1224
18
18
  femagtools/femag.py,sha256=RUkjvkHe5gBElawh4-cbwueplXA5Tjvnu28CPVw6f74,44123
19
19
  femagtools/forcedens.py,sha256=7NNv75Vg9vQ_fy8W4kM2rlSO970zaSmeurhPmdAxsOU,8485
20
- femagtools/fsl.py,sha256=htSzZkguxDsVvIBXi6VK3YRqUbYAlQ_R4jLRfcOmIzw,33872
20
+ femagtools/fsl.py,sha256=wlQkaFslVhbhLYuFJMddlOAOjWoZfeQgBUi6zNS4s-A,33977
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
@@ -48,20 +48,20 @@ femagtools/vbf.py,sha256=9XGfhftmD9carU8ByQ5DwqoR4daq5mJ39eMqruwml0Q,2444
48
48
  femagtools/vtu.py,sha256=Sf83dHIfCKY2km-MIUHKKoj-JKN4PDX7kkPLZXyIYY4,10723
49
49
  femagtools/windings.py,sha256=-PDqzatXJUaMTR4hI1bbY__AAb3fjwfjiS9FEuR-8N8,22305
50
50
  femagtools/dxfsl/__init__.py,sha256=MywcCdpKPKs4qJBJJgeDsikJFJ2P48dbTuNk303f5pM,76
51
- femagtools/dxfsl/area.py,sha256=cYnDtnEuwuDW5R1NKV0s8PUzzQzxhgCUktFqHAjP9K8,56581
51
+ femagtools/dxfsl/area.py,sha256=Y7qNteasOB54hzo-QkDlHdjcym74FKJVdUrKaCFy23I,60813
52
52
  femagtools/dxfsl/areabuilder.py,sha256=Siu11yRcNJiSCWwc865-OvuVhSmLtRQWysbe1-rUcN0,34197
53
53
  femagtools/dxfsl/concat.py,sha256=F6scwesxyOmfmKQ5kGspNCxA71Yz6QgxFL7lTj3hsaI,13385
54
- femagtools/dxfsl/conv.py,sha256=GeRYUvbdcP5vKtNm5S5gU1yyMboGkGNyOqzkHpYbEEo,10086
55
- femagtools/dxfsl/converter.py,sha256=BRIzgg15gqnO-FJ6maVJ1YI3i-elY6Dwbs_-dNTiL94,32412
54
+ femagtools/dxfsl/conv.py,sha256=Z_jf4OTxikr-SoUuBew_wrEj32qcGPyEp7VMtkRJx9M,10747
55
+ femagtools/dxfsl/converter.py,sha256=txsDdMbQxMLXyAC5LV97ZifO49O5oXu-SRM1wqawSUs,33223
56
56
  femagtools/dxfsl/corner.py,sha256=-XPBcnEau-2-SRHLYzlBqCQGaFfgm_DH2qR1mSaFoAs,1311
57
57
  femagtools/dxfsl/dumprenderer.py,sha256=n4AvInjvGIaC2iKZtQaYXXDyJVSQ3uEOFOLD4-xfKRY,1861
58
58
  femagtools/dxfsl/dxfparser.py,sha256=kyXG0kZfNyOgn96MqBgP8RhOQhppfB5NbyRNNybs1C0,13451
59
59
  femagtools/dxfsl/femparser.py,sha256=O8940Q1Mz8MKng6W8M3s9KfTvhDLJ56tfQWtZEW3xMM,2134
60
- femagtools/dxfsl/fslrenderer.py,sha256=PBy3KUlNIqItcxCFnWC-d3OrSrsNFj5vDLLGZW2oq3Q,25081
60
+ femagtools/dxfsl/fslrenderer.py,sha256=6mwQv9D45dgR2rmBovcediwfGEnmLGDAWaIfUo2Qd1o,25257
61
61
  femagtools/dxfsl/functions.py,sha256=F0AjzHfIfq3v-mhDzUOeq3zeYQCEsJl1-XpEyJQsSnQ,11805
62
- femagtools/dxfsl/geom.py,sha256=-hPErBLyAsDh-aq2s54psFqG2AaNr9jVeKMeEVUQF5E,165356
62
+ femagtools/dxfsl/geom.py,sha256=lHmhuDNNM30fTT6p3-cOBkOUI5MKE6PnQ_ShEYDpm58,169937
63
63
  femagtools/dxfsl/journal.py,sha256=S17B7wsrq5QzIUbjgg0ntvnpgH0thHq9aQXO7GdYlQQ,4265
64
- femagtools/dxfsl/machine.py,sha256=3leWkjdMCLX2HgMhw8gNdxTKROhNCKU7KQrDVbBQ8DI,49337
64
+ femagtools/dxfsl/machine.py,sha256=mMi6_eL4b5aZMF67jUS3bXZyr2RorcV9qfJEntejxUk,50098
65
65
  femagtools/dxfsl/plotrenderer.py,sha256=q2cORuxJEf1Ws6oCY9c0gF6N3kDrcI6WOz3u5Vl6R_c,13823
66
66
  femagtools/dxfsl/shape.py,sha256=ZmWw7VTSJs5rcY1Lh99MKo804mO7dSGHdKMIh-nVBow,59904
67
67
  femagtools/dxfsl/svgparser.py,sha256=R8V2V5jE6JyVfzshJVaPgsSuMlQf_pwJTFvrTrKDxZ0,2905
@@ -70,10 +70,10 @@ femagtools/machine/__init__.py,sha256=U8W65K7jr7jDdC1KnJh0WjYd8DFaLnIFVvlh-TKcV9
70
70
  femagtools/machine/afpm.py,sha256=hNyDFRLGmCuWRPZl_u1ztJ4pA-Y_mxLaVvg3UJkzRuE,24766
71
71
  femagtools/machine/effloss.py,sha256=sLB8AXYVAE_AL1Ca41A2EDbn9_7u6xNjaYFjmRPoTDg,13578
72
72
  femagtools/machine/im.py,sha256=3Y54AHMZfAjkvgexx2E-5jxNWzaVQ-SyaETCh7gNBYA,38008
73
- femagtools/machine/pm.py,sha256=4gqYLWACE7C9FzmiHVwh6M2WT7ofNezEIazkAxLae8Q,61704
73
+ femagtools/machine/pm.py,sha256=IfKQPyrVc2AV78rWy2bW1GB1SvM6Ro-XHhOU7RT95Dk,67677
74
74
  femagtools/machine/sizing.py,sha256=nWCfxbyWfbw5-7xu0qZ6zjWNquEPn3fUH-fQeGb6QUc,24307
75
75
  femagtools/machine/sm.py,sha256=G4fHmZngQSRN9Dum7mHaf36b_CvD-u_AQogIFixlnys,37899
76
- femagtools/machine/utils.py,sha256=zi659wCszhXEioKXtRdeyQik2etRFGpoykqfOGiLtTo,21223
76
+ femagtools/machine/utils.py,sha256=lDbOP4HisdOa7Wi-8xLB1jPvwyM_51SFc-xyJYIz4Eo,21238
77
77
  femagtools/moo/__init__.py,sha256=zinmWEOrsEz6DmMX0Dbn4t6_1UR-p4bEGqyR1wUQk_Q,175
78
78
  femagtools/moo/algorithm.py,sha256=lNEf0Bur4yFpIJeLtAC3oIus8sOMWTb7jepFlD28YzE,5445
79
79
  femagtools/moo/population.py,sha256=qGEsm-2Ys_pTkVQv3Zv36HzOlqUxtMvM6NqY_KytsUE,10060
@@ -82,7 +82,7 @@ femagtools/moo/test/AlgorithmTest.py,sha256=KzR1og4bu6NOE61DDKjEMTQdsysmho4LCYmJ
82
82
  femagtools/moo/test/PopulationTest.py,sha256=lG9NeWo0xrslfQRa4tgy1Nj23VJMFIlg_vQ9KUBYnRA,5529
83
83
  femagtools/moo/test/ProblemTest.py,sha256=r5XEfY4LPscDb35TxxPd0lbP3nUmL6_G6vrRo1I3RSg,505
84
84
  femagtools/plot/__init__.py,sha256=dD_wvo6sGc8jvJYD1b0Z7oxCE4O9uQ3Igb5DeAjZDWU,939
85
- femagtools/plot/bch.py,sha256=4f9Q-JZtj9WMjxFUXMXNaSdWdDXN_Be4-F9kOU45xns,28525
85
+ femagtools/plot/bch.py,sha256=_EEPPEqtEPeWco3xlQqUuZft1eF-IXbMNnXyd8pYEJs,28873
86
86
  femagtools/plot/char.py,sha256=iDvrKp_Hz10W7qLjWCtYajKjY01fZbwf_kITDGisPaY,12123
87
87
  femagtools/plot/fieldlines.py,sha256=QtKF4nhnQ_FHHGh9Qez3GVmym0CLhW1ZyIKtk4pzos4,1136
88
88
  femagtools/plot/fluxdens.py,sha256=NlexRJ3f_8CgKoWrV82ZIsAXPrLhwj98uOe8_fUks7A,1082
@@ -129,7 +129,7 @@ femagtools/templates/magnetSector.mako,sha256=db_i1jNJ4TONkBIEKVIWVRZkEJWPwO_r4M
129
129
  femagtools/templates/magnetSectorLinear.mako,sha256=ez2rkZslw66Zy4DCDiLjI2K45nEjGgunl0jsXseO_Zs,727
130
130
  femagtools/templates/magnetShell.mako,sha256=vpyZIZ5tOsrmUVM00Kime7zyu1lK9P61xq78jB8BLdo,1295
131
131
  femagtools/templates/magnetShell2.mako,sha256=4IJBfBTPxuYHr1SAcVvNdQoGd8emwsx8vMKQPI9pRlc,4080
132
- femagtools/templates/mesh-airgap.mako,sha256=QFutdFUnz5lMpjRT9cN0w6EPShccYJfz4yuMqNYoZ1Y,3425
132
+ femagtools/templates/mesh-airgap.mako,sha256=9fESevBQJSIf0uCWJIRqhZaj-2-HEjR3nJl-YfKebPo,3685
133
133
  femagtools/templates/modal_analysis.mako,sha256=Thf62FBqL738qnp1ongPr196GJY27vwElKqPfMWF45s,2298
134
134
  femagtools/templates/modified_steinmetz.mako,sha256=qrJ18XtoU39kjbcdywCJCLObQGaO-eC3Cl-1P4xLZWg,1327
135
135
  femagtools/templates/mult_cal_fast.mako,sha256=FhqRZQaBIIvmx0LgKXVLOIjz7LshoDFHqhkD0QGlX8A,1255
@@ -157,7 +157,7 @@ femagtools/templates/stator3Linear.mako,sha256=pNe3C1wT0W2C0qePo3sEyebW1z_dpTuJz
157
157
  femagtools/templates/stator4.mako,sha256=Jq8pfIuOmmpyGOL1z2aQZfbwMS5-Zyn6OGJ51LCBVKs,1179
158
158
  femagtools/templates/statorBG.mako,sha256=fh0cVOZVWyLojlGxWJoFz2pvdL6Yxy4xzhY-Joc2xeg,893
159
159
  femagtools/templates/statorRing.mako,sha256=sDgDmk71EoE8d4e9cmyqKqRldfC8uKMmpHEjXJGIt_k,2071
160
- femagtools/templates/statorRotor3.mako,sha256=MrU_JCSH8tJEUH09fftJJslkbEeIwOB1WGBSxXqUqeI,4942
160
+ femagtools/templates/statorRotor3.mako,sha256=6NTmHKetgsfi4tsN_OSNqZ08y_KVXLOMs7VkeN6Bngk,5025
161
161
  femagtools/templates/stator_msh.mako,sha256=Neze1ielMCk7TrARyhOra91fFQVT8Phsgk2Omt_aMG8,1799
162
162
  femagtools/templates/therm-dynamic.mako,sha256=pEz7jrUpopK1-RqgulNnrkSaCZDjfLelsVo6cBqmpac,3142
163
163
  femagtools/templates/therm_static.mako,sha256=ulevp4AP-kZ1_qdScPMaX9tLqvvP0t9lFflWTXgUxaE,1310
@@ -212,9 +212,9 @@ tests/moo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
212
212
  tests/moo/test_algorithm.py,sha256=Em8sFm2vzPmuIzRrBBnUQLU_TYuJHSf-kEeozw0XeX4,2563
213
213
  tests/moo/test_population.py,sha256=FvX9LRCxQx0_E2GxHQ5vKwOYFBQiNbT6Lmv5GmNWjTQ,5471
214
214
  tests/moo/test_problem.py,sha256=ALeP4u7g-dFhfwWL8vxivdrrYzVKPjHMCAXzzgyNZbs,467
215
- femagtools-1.7.4.dist-info/LICENSE,sha256=NaQe4uvkszQPJmiRPHecfk-Ab9VSRXo8xQLGNVHTeFo,1362
216
- femagtools-1.7.4.dist-info/METADATA,sha256=mDq3sIVGX9_9OYQa4NObTZud2BH92rKQUJe7GR9bZNM,6156
217
- femagtools-1.7.4.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
218
- femagtools-1.7.4.dist-info/entry_points.txt,sha256=jrvOkZPiN44u1sASeu271VRaVIv5V-uRpN0_N5U_R8c,248
219
- femagtools-1.7.4.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
220
- femagtools-1.7.4.dist-info/RECORD,,
215
+ femagtools-1.7.6.dist-info/LICENSE,sha256=NaQe4uvkszQPJmiRPHecfk-Ab9VSRXo8xQLGNVHTeFo,1362
216
+ femagtools-1.7.6.dist-info/METADATA,sha256=dTUdOh7eh4dgbkfeUTUDK1OPxGSMniFY3sSxQNl_BGg,6156
217
+ femagtools-1.7.6.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
218
+ femagtools-1.7.6.dist-info/entry_points.txt,sha256=jrvOkZPiN44u1sASeu271VRaVIv5V-uRpN0_N5U_R8c,248
219
+ femagtools-1.7.6.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
220
+ femagtools-1.7.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5