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
@@ -5,7 +5,7 @@
5
5
  from __future__ import print_function
6
6
  import numpy as np
7
7
  import logging
8
- from .shape import Element, Circle, Arc, Line, Shape
8
+ from .shape import Element, Circle, Arc, Line
9
9
  from .corner import Corner
10
10
  from .functions import point, points_are_close, distance
11
11
  from .functions import alpha_angle, normalise_angle, middle_angle, third_angle
@@ -14,6 +14,7 @@ from .functions import within_interval, part_of_circle
14
14
  from .functions import less, less_equal, greater, greater_equal
15
15
  logger = logging.getLogger('femagtools.geom')
16
16
 
17
+
17
18
  #############################
18
19
  # Machine #
19
20
  #############################
@@ -170,7 +171,8 @@ class Machine(object):
170
171
 
171
172
  def copy(self, startangle, endangle,
172
173
  airgap=False, inside=True, split=False,
173
- delete_appendices=False):
174
+ delete_appendices=False,
175
+ concatenate_tiny_el=False):
174
176
  if airgap and self.airgap_radius > 0.0:
175
177
  if inside:
176
178
  if self.airgap2_radius > 0.0:
@@ -181,7 +183,8 @@ class Machine(object):
181
183
  startangle, endangle,
182
184
  0.0, new_radius,
183
185
  split=split,
184
- delete_appendices=delete_appendices)
186
+ delete_appendices=delete_appendices,
187
+ concatenate_tiny_el=concatenate_tiny_el)
185
188
  else:
186
189
  new_radius = self.radius
187
190
  gap_radius = max(self.airgap_radius, self.airgap2_radius)
@@ -189,7 +192,8 @@ class Machine(object):
189
192
  startangle, endangle,
190
193
  gap_radius, self.radius+9999,
191
194
  split=split,
192
- delete_appendices=delete_appendices)
195
+ delete_appendices=delete_appendices,
196
+ concatenate_tiny_el=concatenate_tiny_el)
193
197
 
194
198
  circ = Circle(Element(center=self.center,
195
199
  radius=self.airgap_radius))
@@ -200,7 +204,8 @@ class Machine(object):
200
204
  startangle, endangle, 0.0,
201
205
  self.radius+9999,
202
206
  split=split,
203
- delete_appendices=delete_appendices)
207
+ delete_appendices=delete_appendices,
208
+ concatenate_tiny_el=concatenate_tiny_el)
204
209
 
205
210
  if not np.isclose(normalise_angle(startangle),
206
211
  normalise_angle(endangle), 0.0):
@@ -231,6 +236,7 @@ class Machine(object):
231
236
  return clone.get_machine()
232
237
 
233
238
  def copy_mirror(self, startangle, midangle, endangle):
239
+ logger.debug("begin of copy_mirror")
234
240
  geom1 = self.geom.copy_shape(self.radius,
235
241
  startangle,
236
242
  midangle,
@@ -254,6 +260,7 @@ class Machine(object):
254
260
  machine.mirror_geom = geom2
255
261
  machine.mirror_startangle = midangle
256
262
  machine.mirror_endangle = endangle
263
+ logger.debug("end of copy_mirror")
257
264
  return machine
258
265
 
259
266
  def has_mirrored_windings(self):
@@ -279,16 +286,16 @@ class Machine(object):
279
286
  self.endangle += angle
280
287
 
281
288
  def airgap(self, correct_airgap=0.0, correct_airgap2=0.0, atol=0.1):
282
- logger.debug('locking for airgap')
289
+ logger.debug('begin airgap (locking for airgap)')
283
290
  self.airgap_radius = 0.0
284
291
  self.airgap2_radius = 0.0
285
292
 
286
293
  if np.isclose(self.radius, 0.0):
287
- logger.debug('no radius')
294
+ logger.debug('end airgap: no radius')
288
295
  return False
289
296
 
290
297
  if correct_airgap < 0:
291
- logger.debug('no airgap')
298
+ logger.debug('end airgap: no airgap (%s)', correct_airgap)
292
299
  return False # no airgap
293
300
 
294
301
  self.airgaps = []
@@ -354,33 +361,39 @@ class Machine(object):
354
361
  logger.error("No airgap with radius {} found"
355
362
  .format(correct_airgap))
356
363
  self.show_airgap_candidates(airgap_candidates, False)
364
+ logger.debug("end airgap: bad")
357
365
  return True # bad exit
358
366
 
359
367
  if correct_airgap2 > 0.0 and self.airgap2_radius == 0.0:
360
368
  logger.error("No airgap2 with radius {} found"
361
369
  .format(correct_airgap2))
362
370
  self.show_airgap_candidates(airgap_candidates, False)
371
+ logger.debug("end airgap: bad")
363
372
  return True # bad exit
364
373
 
365
374
  if len(self.airgaps) == 0:
366
- logger.debug('No airgap found')
375
+ logger.debug('end airgap: No airgap found')
367
376
  return False # no airgaps found
368
377
 
369
378
  if self.airgap_radius > 0.0:
379
+ logger.debug("end airgap: radius=%s", self.airgap_radius)
370
380
  return False # correct airgap set
371
381
 
372
382
  gaps = [c for b, c, d in airgap_candidates if b == 0]
373
383
 
374
384
  if len(gaps) == 1: # one candidate without border intersection
375
385
  self.airgap_radius = gaps[0].radius
386
+ logger.debug("end airgap: radius=%s", self.airgap_radius)
376
387
  return False # ok
377
388
 
378
389
  if len(airgap_candidates) == 1: # one candidate found
379
390
  self.airgap_radius = airgap_candidates[0][1].radius
391
+ logger.debug("end airgap: radius=%s", self.airgap_radius)
380
392
  return False # ok
381
393
 
382
394
  self.airgap_radius = self.show_airgap_candidates(airgap_candidates,
383
395
  True)
396
+ logger.debug("end airgap: radius=%s", self.airgap_radius)
384
397
  return False # ok
385
398
 
386
399
  def show_airgap_candidates(self, airgap_candidates, get_one):
@@ -451,7 +464,7 @@ class Machine(object):
451
464
  self.geom.delete_circle((0.0, 0.0), first_dist)
452
465
 
453
466
  def repair_hull(self):
454
- logger.debug('repair_hull')
467
+ logger.debug('begin repair_hull(%s, %s)', self.startangle, self.endangle)
455
468
  if self.is_full() and not self.has_airgap():
456
469
  self.delete_center_circle()
457
470
 
@@ -468,18 +481,31 @@ class Machine(object):
468
481
  logger.debug('end of repair_hull')
469
482
 
470
483
  def repair_hull_geom(self, geom, startangle, endangle):
471
- logger.debug('repair_hull_geom')
484
+ logger.debug('begin repair_hull_geom (%s, %s)', startangle, endangle)
472
485
 
486
+ rtol = 1e-4
487
+ atol = 1e-4
473
488
  c_corner = Corner(self.center, self.center)
474
- start_corners = geom.get_corner_list(self.center, startangle)
475
- end_corners = geom.get_corner_list(self.center, endangle)
489
+ start_c_added, start_corners = geom.get_corner_list(self.center, startangle,
490
+ rtol=rtol, atol=atol)
491
+ end_c_added, end_corners = geom.get_corner_list(self.center, endangle,
492
+ rtol=rtol, atol=atol)
493
+ if start_c_added or end_c_added:
494
+ rtol = 1e-3
495
+ atol = 1e-3
496
+ start_c_added, start_corners = geom.get_corner_list(self.center, startangle,
497
+ rtol=rtol, atol=atol)
498
+ end_c_added, end_corners = geom.get_corner_list(self.center, endangle,
499
+ rtol=rtol, atol=atol)
476
500
 
477
501
  geom.repair_hull_line(self.center,
478
502
  startangle, start_corners,
479
- c_corner in end_corners)
503
+ c_corner in end_corners,
504
+ rtol=rtol, atol=atol)
480
505
  geom.repair_hull_line(self.center,
481
506
  endangle, end_corners,
482
- c_corner in start_corners)
507
+ c_corner in start_corners,
508
+ rtol=rtol, atol=atol)
483
509
  logger.debug('end of repair_hull_geom')
484
510
 
485
511
  def create_stator_auxiliary_lines(self):
@@ -657,7 +683,8 @@ class Machine(object):
657
683
  return None
658
684
 
659
685
  machine_slice = self.copy(self.geom.symmetry_startangle(),
660
- self.geom.symmetry_endangle())
686
+ self.geom.symmetry_endangle(),
687
+ concatenate_tiny_el=True)
661
688
  machine_slice.clear_cut_lines()
662
689
  machine_slice.repair_hull()
663
690
  machine_slice.rotate_to(0.0)
@@ -287,7 +287,7 @@ class PlotRenderer(object):
287
287
 
288
288
  self.ax.axis('scaled')
289
289
  self.ax.set_aspect('equal')
290
-
290
+
291
291
  self.ax.set_xlim(x_min, x_max)
292
292
  self.ax.set_ylim(y_min, y_max)
293
293
 
@@ -360,7 +360,7 @@ class PlotRenderer(object):
360
360
  area.render(self, 'red', with_nodes=True)
361
361
 
362
362
  self.ax.axis('scaled')
363
- self.ax.set_aspect('equal')
363
+ self.ax.set_aspect('equal')
364
364
  pl.show()
365
365
 
366
366
  def draw_slot(self, id, slot, ax):
femagtools/dxfsl/shape.py CHANGED
@@ -9,7 +9,6 @@
9
9
  """
10
10
  from __future__ import print_function
11
11
  import numpy as np
12
- import sys
13
12
  import logging
14
13
  from .functions import less_equal, greater_equal
15
14
  from .functions import distance, line_m, line_n
@@ -18,7 +17,7 @@ from .functions import alpha_line, alpha_angle, alpha_triangle
18
17
  from .functions import normalise_angle, min_angle, max_angle, get_angle_of_arc
19
18
  from .functions import lines_intersect_point, nodes_are_equal
20
19
  from .functions import is_angle_inside, intersect_point
21
- from .functions import middle_angle
20
+ from .functions import middle_angle, middle_point_of_line
22
21
 
23
22
  logger = logging.getLogger('femagtools.geom')
24
23
 
@@ -50,7 +49,10 @@ class Shape(object):
50
49
  if hasattr(s, 'my_attrs'):
51
50
  self.my_attrs = []
52
51
  for a in s.my_attrs:
53
- self.my_attrs.append(a)
52
+ self.my_attrs.append(a)
53
+
54
+ def classname(self):
55
+ return "Shape"
54
56
 
55
57
  def get_my_color(self):
56
58
  if hasattr(self, 'my_color'):
@@ -209,8 +211,8 @@ class Shape(object):
209
211
  d1 = distance(n, self.n1)
210
212
  d2 = distance(n, self.n2)
211
213
  if d1 == d2:
212
- logger.info("distances of %s and %s are equal (%s / %s)",
213
- self.n1, self.n2, d1, d2)
214
+ logger.warning("distances of %s and %s are equal (%s / %s)",
215
+ self.n1, self.n2, d1, d2)
214
216
  raise ValueError('both nodes are equal in element')
215
217
 
216
218
  if d1 < d2:
@@ -307,6 +309,9 @@ class Circle(Shape):
307
309
  self.n1 = None
308
310
  self.n2 = None
309
311
 
312
+ def classname(self):
313
+ return "Circle"
314
+
310
315
  def render(self, renderer, color='blue', with_nodes=False):
311
316
  tmp_color = self.get_my_color()
312
317
  if not tmp_color:
@@ -544,6 +549,19 @@ class Circle(Shape):
544
549
  assert(len(points) == 0)
545
550
  return []
546
551
 
552
+ def cut_into_halves(self):
553
+ """ return two arcs
554
+ """
555
+ a1 = Arc(Element(center=self.center,
556
+ radius=self.radius,
557
+ start_angle=0.0,
558
+ end_angle=180.0))
559
+ a2 = Arc(Element(center=self.center,
560
+ radius=self.radius,
561
+ start_angle=180.0,
562
+ end_angle=0.0))
563
+ return a1, a2
564
+
547
565
  def get_angle_of_arc(self):
548
566
  return np.pi*2.0
549
567
 
@@ -608,6 +626,9 @@ class Arc(Circle):
608
626
  else:
609
627
  self.rtheta = None
610
628
 
629
+ def classname(self):
630
+ return "Arc"
631
+
611
632
  def render(self, renderer, color='blue', with_nodes=False):
612
633
  tmp_color = self.get_my_color()
613
634
  if not tmp_color:
@@ -715,8 +736,9 @@ class Arc(Circle):
715
736
  points.append(e.p2)
716
737
 
717
738
  elif e.is_point_inside(self.p2, rtol, atol):
718
- if not points_are_close(self.p1, e.p1):
739
+ if not points_are_close(self.p1, e.p1, rtol=rtol, atol=atol):
719
740
  logger.error("FATAL ERROR in overlapping_shape() of Arc")
741
+
720
742
  raise ValueError('FATAL ERROR in overlapping_shape() of Arc')
721
743
  points.append(e.p1)
722
744
  points.append(self.p2)
@@ -808,6 +830,20 @@ class Arc(Circle):
808
830
  assert(len(points_inside) == 0)
809
831
  return []
810
832
 
833
+ def cut_into_halves(self):
834
+ """ return two arcs
835
+ """
836
+ midangle = middle_angle(self.startangle, self.endangle)
837
+ a1 = Arc(Element(center=self.center,
838
+ radius=self.radius,
839
+ start_angle=self.startangle*180/np.pi,
840
+ end_angle=midangle*180/np.pi))
841
+ a2 = Arc(Element(center=self.center,
842
+ radius=self.radius,
843
+ start_angle=midangle*180/np.pi,
844
+ end_angle=self.endangle*180/np.pi))
845
+ return a1, a2
846
+
811
847
  def concatenate_arc(self, n1, n2, el):
812
848
  if not points_are_close(self.center, el.center):
813
849
  return None
@@ -817,9 +853,11 @@ class Arc(Circle):
817
853
  if np.isclose(self.startangle, el.endangle):
818
854
  start_angle = el.startangle
819
855
  end_angle = self.endangle
820
- else:
856
+ elif np.isclose(el.startangle, self.endangle):
821
857
  start_angle = self.startangle
822
858
  end_angle = el.endangle
859
+ else:
860
+ return None
823
861
 
824
862
  logger.debug("concatenate_arc: start=%s, end=%s",
825
863
  start_angle,
@@ -833,30 +871,30 @@ class Arc(Circle):
833
871
  def is_point_inside(self, p, rtol=1e-03, atol=1e-03, include_end=False):
834
872
  """ returns true if p is on arc
835
873
  """
836
- logger.debug("is_point_inside: p=%s", p)
874
+ # logger.debug("is_point_inside: p=%s", p)
837
875
  d = distance(p, self.center)
838
876
  if not np.isclose(d, self.radius, rtol=rtol, atol=atol):
839
- logger.debug(" <== RADIUS %s, DISTANCE %s",
840
- self.radius, d)
877
+ # logger.debug(" <== RADIUS %s, DISTANCE %s",
878
+ # self.radius, d)
841
879
  return False
842
880
  if points_are_close(p, self.p1, rtol=rtol, atol=atol):
843
- logger.debug(" <== CLOSE TO P1 %s: rtol=%s, atol=%s",
844
- self.p1, rtol, atol)
881
+ # logger.debug(" <== CLOSE TO P1 %s: rtol=%s, atol=%s",
882
+ # self.p1, rtol, atol)
845
883
  return include_end
846
884
  elif points_are_close(p, self.p2, rtol=rtol, atol=atol):
847
- logger.debug(" <== CLOSE TO P2 %s: rtol=%s, atol=%s",
848
- self.p2, rtol, atol)
885
+ # logger.debug(" <== CLOSE TO P2 %s: rtol=%s, atol=%s",
886
+ # self.p2, rtol, atol)
849
887
  return include_end
850
888
  elif points_are_close(self.p1, self.p2, rtol=rtol, atol=atol):
851
- logger.debug(" <== P1 AND P2 CLOSE TOGETHER")
889
+ # logger.debug(" <== P1 AND P2 CLOSE TOGETHER")
852
890
  return False
853
891
 
854
892
  alpha_p1 = alpha_line(self.center, self.p1)
855
893
  alpha_p2 = alpha_line(self.center, self.p2)
856
894
  alpha_p = alpha_line(self.center, p)
857
895
  alpha_inside = is_angle_inside(alpha_p1, alpha_p2, alpha_p)
858
- logger.debug("is_point_inside: %s (%s, %s ,%s)",
859
- alpha_inside, alpha_p1, alpha_p2, alpha_p)
896
+ # logger.debug("is_point_inside: %s (%s, %s ,%s)",
897
+ # alpha_inside, alpha_p1, alpha_p2, alpha_p)
860
898
  return alpha_inside
861
899
 
862
900
  def is_angle_inside(self, alpha, rtol=1e-03, atol=1e-03,
@@ -889,7 +927,7 @@ class Arc(Circle):
889
927
  self.startangle = np.arctan2(p1[1], p1[0])
890
928
  self.endangle = np.arctan2(p2[1], p2[0])
891
929
  if self.rtheta is not None:
892
- self.rtheta = self.rtheta + alpha
930
+ self.rtheta = self.rtheta + dest_alpha
893
931
  return self
894
932
 
895
933
  def minmax(self):
@@ -1054,6 +1092,9 @@ class Line(Shape):
1054
1092
  self.n1 = None
1055
1093
  self.n2 = None
1056
1094
 
1095
+ def classname(self):
1096
+ return "Line"
1097
+
1057
1098
  def render(self, renderer, color='blue', with_nodes=False):
1058
1099
  tmp_color = self.get_my_color()
1059
1100
  if not tmp_color:
@@ -1186,9 +1227,29 @@ class Line(Shape):
1186
1227
  return split_lines
1187
1228
  return []
1188
1229
 
1230
+ def cut_into_halves(self):
1231
+ """ return two lines
1232
+ """
1233
+ pm = middle_point_of_line(self.p1, self.p2)
1234
+ l1 = Line(Element(start=self.p1, end=pm))
1235
+ l2 = Line(Element(start=pm, end=self.p2))
1236
+ return l1, l2
1237
+
1189
1238
  def concatenate_line(self, n1, n2, el):
1190
- if np.isclose(self.m(999999.0), el.m(999999.0)):
1239
+ if not np.isclose(self.m(999999.0), el.m(999999.0)):
1240
+ return None
1241
+
1242
+ if n1 and n2:
1191
1243
  return Line(Element(start=n1, end=n2))
1244
+
1245
+ if points_are_close(self.p1, el.p1):
1246
+ return Line(Element(start=self.p2, end=el.p2))
1247
+ if points_are_close(self.p1, el.p2):
1248
+ return Line(Element(start=self.p2, end=el.p1))
1249
+ if points_are_close(self.p2, el.p1):
1250
+ return Line(Element(start=self.p1, end=el.p2))
1251
+ if points_are_close(self.p2, el.p2):
1252
+ return Line(Element(start=self.p1, end=el.p1))
1192
1253
  return None
1193
1254
 
1194
1255
  def is_point_inside(self, point,
@@ -1293,6 +1354,9 @@ class Point(Shape):
1293
1354
  def __init__(self, p):
1294
1355
  self.p1 = p
1295
1356
 
1357
+ def classname(self):
1358
+ return "Point"
1359
+
1296
1360
  def render(self, renderer):
1297
1361
  renderer.point(self.p1)
1298
1362
 
@@ -1301,6 +1365,7 @@ class Point(Shape):
1301
1365
  self.p1 = (n[0], n[1])
1302
1366
  return self
1303
1367
 
1368
+
1304
1369
  def is_Circle(e):
1305
1370
  return isinstance(e, Circle) and not isinstance(e, Arc)
1306
1371
 
femagtools/femag.py CHANGED
@@ -90,7 +90,7 @@ def get_shortCircuit_parameters(bch, nload):
90
90
  fc_radius=bch.machine['fc_radius'],
91
91
  lfe=bch.armatureLength/1e3,
92
92
  pocfilename=bch.machine['pocfile'],
93
- num_par_wdgs=bch.machine['num_par_wdgs'],
93
+ num_par_wdgs=bch.machine.get('num_par_wdgs', 0),
94
94
  calculationMode='shortcircuit')
95
95
  except (KeyError, AttributeError, IndexError):
96
96
  raise FemagError("missing pm/Rel-Sim results")
@@ -222,6 +222,12 @@ class BaseFemag(object):
222
222
  pass
223
223
  builder = femagtools.fsl.Builder(self.templatedirs)
224
224
  if simulation:
225
+ if 'num_par_wdgs' not in simulation:
226
+ try:
227
+ num_par_wdgs = self.model.winding['num_par_wdgs']
228
+ simulation['num_par_wdgs'] = num_par_wdgs
229
+ except:
230
+ pass
225
231
  set_magnet_properties(self.model, simulation, self.magnets)
226
232
  return builder.create(self.model, simulation,
227
233
  self.magnets, self.condMat)
@@ -351,6 +357,16 @@ class BaseFemag(object):
351
357
 
352
358
  def readResult(self, simulation, bch=None):
353
359
  if simulation:
360
+ if simulation['calculationMode'] == "fieldcalc":
361
+ nc = self.read_nc()
362
+ pmod = nc.poles_sim
363
+ r = {'airgap': ag.read(
364
+ os.path.join(self.workdir, 'bag.dat'), pmod=pmod)}
365
+ if 'plots' in simulation:
366
+ if 'field_lines' in simulation['plots']:
367
+ r['field_lines'] = os.path.join(
368
+ self.workdir, 'field.svg')
369
+ return r
354
370
  if simulation['calculationMode'] == "pm_sym_loss":
355
371
  return self.read_los(self.modelname)
356
372
 
@@ -365,7 +381,8 @@ class BaseFemag(object):
365
381
 
366
382
  if simulation['calculationMode'] == 'therm-dynamic':
367
383
  temp = [[float(n) for n in l.split()]
368
- for l in (pathlib.Path(self.workdir) / 'temperature.dat').read_text().split('\n') if l]
384
+ for l in (pathlib.Path(self.workdir) /
385
+ 'temperature.dat').read_text().split('\n') if l]
369
386
  ttemp = list(zip(*temp))
370
387
  return {'t': ttemp[0], 'temperature': ttemp[1]}
371
388
 
@@ -383,9 +400,10 @@ class BaseFemag(object):
383
400
  set_magnet_properties(self.model, simulation, self.magnets)
384
401
  fslcmds = (builder.open_model(self.model) +
385
402
  builder.create_shortcircuit(simulation))
403
+ fslfile = 'shortcicuit.fsl'
386
404
  with open(os.path.join(self.workdir, fslfile), 'w') as f:
387
405
  f.write('\n'.join(fslcmds))
388
- self.run(fslfile, options)
406
+ self.run(fslfile) #, options?
389
407
  bchfile = self.get_bch_file(self.modelname)
390
408
  if bchfile:
391
409
  bchsc = femagtools.bch.Reader()
femagtools/fsl.py CHANGED
@@ -484,7 +484,11 @@ class Builder:
484
484
  if not hasattr(model, 'stator'):
485
485
  setattr(model, 'stator', {})
486
486
  model.stator['num_slots'] = conv.get('tot_num_slot')
487
- model.stator['num_slots_gen'] = conv.get('num_sl_gen')
487
+ if model.stator.get('num_slots_gen', 0):
488
+ if model.stator['num_slots'] % model.stator['num_slots_gen'] > 0:
489
+ model.stator['num_slots_gen'] = conv.get('num_sl_gen')
490
+ else:
491
+ model.stator['num_slots_gen'] = conv.get('num_sl_gen')
488
492
  if 'fsl_stator' in conv:
489
493
  self.fsl_stator = True
490
494
  model.stator['dxf'] = dict(fsl=conv['fsl_stator'])
@@ -633,15 +637,23 @@ class Builder:
633
637
 
634
638
  def create_analysis(self, sim):
635
639
  pfefunc = sim.get('loss_funct', '')
640
+ custom_fefunc = ['']
636
641
  if pfefunc:
637
642
  sim['loss_funct'] = 1 # 3?
643
+ if pfefunc == 'bertotti' or 'modified_steinmetz':
644
+ custom_fefunc = self.__render(sim['PVFE_FSL'], pfefunc)
645
+ else:
646
+ custom_fefunc = pfefunc.split('\n')
647
+
638
648
  airgap_induc = (self.create_airgap_induc()
639
649
  if sim.get('airgap_induc', 0) else [])
640
- felosses = pfefunc.split('\n') + self.create_fe_losses(sim)
650
+ felosses = custom_fefunc + self.create_fe_losses(sim)
641
651
  fslcalc = (self.__render(sim, sim.get('calculationMode')) +
642
652
  airgap_induc)
653
+ '''
643
654
  if pfefunc:
644
655
  sim['loss_funct'] = pfefunc
656
+ '''
645
657
 
646
658
  if sim.get('calculationMode') in ('cogg_calc',
647
659
  'ld_lq_fast',
@@ -14,13 +14,14 @@ import logging
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
16
 
17
- def __scale_losses(losses, lfe):
17
+ def __scale_losses(losses, rlfe):
18
18
  if losses:
19
- l = {k: lfe*np.array(losses[k]) for k in (
19
+ l = {k: rlfe*np.array(losses[k]) for k in (
20
20
  'styoke_hyst', 'styoke_eddy',
21
21
  'stteeth_hyst', 'stteeth_eddy',
22
+ 'styoke_excess', 'stteeth_excess', 'rotor_excess',
22
23
  'rotor_hyst', 'rotor_eddy',
23
- 'magnet')}
24
+ 'magnet') if k in losses}
24
25
  l['speed'] = losses['speed']
25
26
  return l
26
27
  return {}
@@ -66,18 +67,15 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
66
67
 
67
68
  psid = rwdg*rlfe*dqp['psid']
68
69
  psiq = rwdg*rlfe*dqp['psiq']
69
- try:
70
- losses = __scale_losses(dqp['losses'], rlfe)
71
- losses['ef'] = dqpars[-1]['losses']['ef']
72
- losses['eh'] = dqpars[-1]['losses']['ef']
73
- except KeyError as e:
74
- logger.warning(e)
75
- losses = {}
70
+ losses = __scale_losses(dqp['losses'], rlfe)
71
+ losses['ef'] = dqpars[-1]['losses']['ef']
72
+ losses['eh'] = dqpars[-1]['losses']['ef']
73
+
76
74
  if 'psidq' in eecpars:
77
75
  machine = PmRelMachinePsidq(
78
76
  eecpars['m'], eecpars['p'],
79
- r1=eecpars['r1']*rlfe*rwdg**2,
80
- ls=eecpars['ls1']*rwdg**2,
77
+ r1=eecpars.get('r1', 0)*rlfe*rwdg**2,
78
+ ls=eecpars.get('ls1', 0)*rwdg**2,
81
79
  psid=psid,
82
80
  psiq=psiq,
83
81
  losses=losses,
@@ -90,8 +88,8 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
90
88
  i1 = np.array(dqp['i1'])/rwdg
91
89
  machine = PmRelMachineLdq(
92
90
  eecpars['m'], eecpars['p'],
93
- r1=eecpars['r1']*rlfe*rwdg**2,
94
- ls=eecpars['ls1']*rwdg**2,
91
+ r1=eecpars.get('r1', 0)*rlfe*rwdg**2,
92
+ ls=eecpars.get('ls1', 0)*rwdg**2,
95
93
  psid=psid,
96
94
  psiq=psiq,
97
95
  losses=losses,
@@ -103,7 +101,7 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
103
101
 
104
102
  # must be an induction machine (TODO: check scaling)
105
103
  pars = copy.deepcopy(eecpars)
106
- pars['r1'] = rlfe*rwdg**2*pars['r1']
104
+ pars['r1'] = rlfe*rwdg**2*pars.get('r1', 0)
107
105
  pars['lsigma1'] = rlfe*pars['lsigma1']
108
106
  pars['lsigma2'] = rlfe*pars['lsigma2']
109
107
  pars['psiref'] = rwdg*rlfe*pars['psiref']
@@ -119,24 +117,6 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
119
117
  return InductionMachine(pars)
120
118
 
121
119
 
122
- def __scale_losses(losses, rlfe):
123
- if losses:
124
- l = {k: rlfe*np.array(losses[k]) for k in (
125
- 'styoke_hyst', 'styoke_eddy',
126
- 'stteeth_hyst', 'stteeth_eddy',
127
- 'rotor_hyst', 'rotor_eddy',
128
- 'magnet')}
129
- if 'styoke_exc' in losses:
130
- l.update({k: rlfe*np.array(losses[k])
131
- for k in (
132
- 'styoke_exc',
133
- 'stteeth_exc',
134
- 'rotor_exc')})
135
- l['speed'] = losses['speed']
136
- return l
137
- return {}
138
-
139
-
140
120
  def create(bch, r1, ls, lfe=1, wdg=1):
141
121
  """create PmRelMachine from BCH
142
122