femagtools 1.8.0__py3-none-any.whl → 1.8.2__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 +1 -1
- femagtools/dxfsl/area.py +47 -3
- femagtools/dxfsl/areabuilder.py +93 -45
- femagtools/dxfsl/conv.py +0 -5
- femagtools/dxfsl/converter.py +92 -33
- femagtools/dxfsl/fslrenderer.py +14 -5
- femagtools/dxfsl/geom.py +245 -210
- femagtools/dxfsl/machine.py +166 -11
- femagtools/dxfsl/shape.py +46 -1
- femagtools/dxfsl/svgparser.py +1 -1
- femagtools/dxfsl/symmetry.py +115 -30
- femagtools/ecloss.py +13 -8
- femagtools/femag.py +61 -29
- femagtools/fsl.py +21 -6
- femagtools/machine/__init__.py +5 -4
- femagtools/machine/afpm.py +41 -15
- femagtools/machine/sizing.py +189 -11
- femagtools/machine/sm.py +5 -11
- femagtools/machine/utils.py +2 -2
- femagtools/mcv.py +2 -3
- femagtools/model.py +4 -3
- femagtools/parstudy.py +1 -1
- femagtools/plot/nc.py +2 -2
- femagtools/templates/afm_rotor.mako +4 -0
- femagtools/templates/prepare_thermal.mako +57 -54
- {femagtools-1.8.0.dist-info → femagtools-1.8.2.dist-info}/METADATA +1 -1
- {femagtools-1.8.0.dist-info → femagtools-1.8.2.dist-info}/RECORD +32 -32
- tests/test_mcv.py +1 -1
- {femagtools-1.8.0.dist-info → femagtools-1.8.2.dist-info}/LICENSE +0 -0
- {femagtools-1.8.0.dist-info → femagtools-1.8.2.dist-info}/WHEEL +0 -0
- {femagtools-1.8.0.dist-info → femagtools-1.8.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.0.dist-info → femagtools-1.8.2.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/machine.py
CHANGED
@@ -14,6 +14,7 @@ from femagtools.dxfsl.functions import alpha_angle, normalise_angle, middle_angl
|
|
14
14
|
from femagtools.dxfsl.functions import alpha_line, line_m, line_n, mirror_point
|
15
15
|
from femagtools.dxfsl.functions import within_interval, part_of_circle
|
16
16
|
from femagtools.dxfsl.functions import less, less_equal, greater, greater_equal
|
17
|
+
from femagtools.dxfsl.journal import Journal, getJournal
|
17
18
|
logger = logging.getLogger('femagtools.geom')
|
18
19
|
|
19
20
|
|
@@ -38,6 +39,7 @@ class Machine(object):
|
|
38
39
|
self.airgap2_radius = 0.0
|
39
40
|
self.airgap_second = None
|
40
41
|
self.previous_machine = None
|
42
|
+
self.journal = getJournal()
|
41
43
|
|
42
44
|
if not self.center:
|
43
45
|
raise ValueError("FATAL ERROR: no center in Geometry")
|
@@ -245,16 +247,21 @@ class Machine(object):
|
|
245
247
|
startangle=self.startangle,
|
246
248
|
endangle=self.endangle)
|
247
249
|
|
248
|
-
def
|
250
|
+
def clone(self):
|
249
251
|
clone = self.geom.copy_shape(self.radius,
|
250
252
|
0.0, 2*np.pi,
|
251
|
-
0.0,
|
252
|
-
|
253
|
+
0.0,
|
254
|
+
self.radius+9999,
|
255
|
+
concatenate=False,
|
256
|
+
connect=False)
|
253
257
|
clone.kind = self.geom.kind
|
254
258
|
clone.sym_part = self.geom.sym_part
|
255
259
|
clone.sym_counterpart = self.geom.sym_counterpart
|
256
260
|
clone.alfa = self.geom.alfa
|
257
|
-
|
261
|
+
return Machine(clone,
|
262
|
+
radius = self.radius,
|
263
|
+
startangle=self.startangle,
|
264
|
+
endangle=self.endangle)
|
258
265
|
|
259
266
|
def copy_mirror(self, startangle, midangle, endangle):
|
260
267
|
logger.debug("begin of copy_mirror")
|
@@ -530,7 +537,7 @@ class Machine(object):
|
|
530
537
|
logger.debug('begin repair_hull_geom (%s, %s)', startangle, endangle)
|
531
538
|
|
532
539
|
rtol = 1e-3
|
533
|
-
atol = 1e-
|
540
|
+
atol = 1e-3
|
534
541
|
c_corner = Corner(self.center, self.center)
|
535
542
|
start_c_added, start_corners = geom.get_corner_list(self.center, startangle,
|
536
543
|
rtol=rtol, atol=atol)
|
@@ -554,8 +561,9 @@ class Machine(object):
|
|
554
561
|
rtol=rtol, atol=atol)
|
555
562
|
logger.debug('end of repair_hull_geom')
|
556
563
|
|
557
|
-
def
|
558
|
-
self.geom.
|
564
|
+
def create_boundary_nodes(self):
|
565
|
+
if self.geom.create_boundary_nodes(self.center, self.startangle, self.endangle):
|
566
|
+
logger.debug("___additional boundary nodes created___")
|
559
567
|
|
560
568
|
def create_auxiliary_lines(self):
|
561
569
|
logger.debug("create_auxiliary_lines")
|
@@ -587,8 +595,34 @@ class Machine(object):
|
|
587
595
|
return w
|
588
596
|
|
589
597
|
def slot_area(self):
|
590
|
-
|
591
|
-
|
598
|
+
return self.geom.area_size_of_type(AREA.TYPE_WINDINGS)
|
599
|
+
|
600
|
+
def get_winding_symmetry(self, inside=False):
|
601
|
+
logger.debug("begin of get_winding_symmetry")
|
602
|
+
symmetry = Symmetry(geom=self.geom,
|
603
|
+
startangle=self.startangle,
|
604
|
+
endangle=self.endangle)
|
605
|
+
parts = symmetry.get_winding_symmetry(inside=inside)
|
606
|
+
logger.debug("end of get_winding_symmetry (parts=%s)", parts)
|
607
|
+
return parts
|
608
|
+
|
609
|
+
def get_magnet_symmetry(self):
|
610
|
+
logger.debug("begin of get_magnet_symmetry")
|
611
|
+
symmetry = Symmetry(geom=self.geom,
|
612
|
+
startangle=self.startangle,
|
613
|
+
endangle=self.endangle)
|
614
|
+
parts = symmetry.get_magnet_symmetry()
|
615
|
+
logger.debug("end of get_magnet_symmetry (parts=%s)", parts)
|
616
|
+
return parts
|
617
|
+
|
618
|
+
def get_symmetry(self):
|
619
|
+
logger.debug("begin of get_symmetry")
|
620
|
+
symmetry = Symmetry(geom=self.geom,
|
621
|
+
startangle=self.startangle,
|
622
|
+
endangle=self.endangle)
|
623
|
+
parts = symmetry.find_symmetry()
|
624
|
+
logger.debug("end of get_symmetry (parts=%s)", parts)
|
625
|
+
return parts
|
592
626
|
|
593
627
|
def find_symmetry(self, sym_tolerance, is_inner, is_outer, plt):
|
594
628
|
logger.debug("begin of find_symmetry")
|
@@ -758,6 +792,97 @@ class Machine(object):
|
|
758
792
|
self.geom.symmetry_endangle()))
|
759
793
|
return machine_slice
|
760
794
|
|
795
|
+
def get_forced_winding_slice(self):
|
796
|
+
logger.debug("get_forced_winding_slice()")
|
797
|
+
if not self.geom.is_outer:
|
798
|
+
return None
|
799
|
+
|
800
|
+
areas = len(self.geom.area_list)
|
801
|
+
winding_areas = self.geom.num_of_windings()
|
802
|
+
iron_areas = self.geom.num_of_irons()
|
803
|
+
air_areas = self.geom.num_areas_of_type((AREA.TYPE_AIR,))
|
804
|
+
|
805
|
+
if not (winding_areas + iron_areas + air_areas == areas):
|
806
|
+
logger.warning("Warning: strange areas in stator")
|
807
|
+
|
808
|
+
if winding_areas == 0:
|
809
|
+
return self.get_possible_windings()
|
810
|
+
|
811
|
+
if winding_areas < 2:
|
812
|
+
return None # nothing to do
|
813
|
+
parts = self.get_winding_symmetry()
|
814
|
+
if parts < 2:
|
815
|
+
return None # nothing to do
|
816
|
+
return self.get_symmetry_slice()
|
817
|
+
|
818
|
+
def get_possible_windings(self, EESM=False, single=False):
|
819
|
+
if not self.geom.is_outer:
|
820
|
+
return None
|
821
|
+
|
822
|
+
machine = self.clone()
|
823
|
+
machine.repair_hull()
|
824
|
+
machine.set_alfa_and_corners()
|
825
|
+
machine.geom.set_subregion_parameters(self.startangle,
|
826
|
+
self.endangle)
|
827
|
+
machine.geom.looking_for_corners()
|
828
|
+
dist_start = machine.geom.dist_start_min_corner()
|
829
|
+
dist_end = machine.geom.dist_end_min_corner()
|
830
|
+
|
831
|
+
if not np.isclose(dist_start, dist_end, rtol=1e-3, atol=1e-3):
|
832
|
+
angle = machine.geom.alfa
|
833
|
+
if dist_start > dist_end:
|
834
|
+
machine.mirror_all_areas(self.startangle)
|
835
|
+
machine.rotate_to(angle)
|
836
|
+
machine.geom.create_list_of_areas(delete=True)
|
837
|
+
machine.startangle -= angle
|
838
|
+
else:
|
839
|
+
machine.mirror_all_areas(self.endangle)
|
840
|
+
machine.endangle += angle
|
841
|
+
machine.set_alfa_and_corners()
|
842
|
+
machine.part = machine.part_of_circle()
|
843
|
+
machine.geom.set_subregion_parameters(self.startangle,
|
844
|
+
self.endangle)
|
845
|
+
machine.geom.looking_for_corners()
|
846
|
+
|
847
|
+
if machine.geom.close_outer_winding_areas():
|
848
|
+
machine.geom.create_list_of_areas(delete=True)
|
849
|
+
machine.geom.set_subregion_parameters(self.startangle,
|
850
|
+
self.endangle)
|
851
|
+
machine.geom.looking_for_corners()
|
852
|
+
parts = machine.get_winding_symmetry(inside=True)
|
853
|
+
|
854
|
+
if parts == 1:
|
855
|
+
return machine
|
856
|
+
if parts > 1:
|
857
|
+
return machine.get_symmetry_slice()
|
858
|
+
|
859
|
+
return machine
|
860
|
+
|
861
|
+
def get_forced_magnet_slice(self):
|
862
|
+
logger.debug("get_forced_magnet_slice()")
|
863
|
+
areas = len(self.geom.area_list)
|
864
|
+
magnet_areas = self.geom.num_of_magnets()
|
865
|
+
iron_areas = self.geom.num_of_irons()
|
866
|
+
air_areas = self.geom.num_areas_of_type((AREA.TYPE_AIR,))
|
867
|
+
|
868
|
+
if magnet_areas < 2:
|
869
|
+
return None # nothing to do
|
870
|
+
parts = self.get_magnet_symmetry()
|
871
|
+
|
872
|
+
if parts < 2:
|
873
|
+
return None # nothing to do
|
874
|
+
slice = self.get_symmetry_slice()
|
875
|
+
match = slice.geom.min_max_corners_match()
|
876
|
+
while parts > 1 and not match:
|
877
|
+
parts = parts - 1
|
878
|
+
self.geom.rotate_symmetry_parameters()
|
879
|
+
slice = self.get_symmetry_slice()
|
880
|
+
match = slice.geom.min_max_corners_match()
|
881
|
+
if match:
|
882
|
+
slice.geom.set_rotor()
|
883
|
+
return slice
|
884
|
+
return None
|
885
|
+
|
761
886
|
def get_forced_symmetry(self, part):
|
762
887
|
logger.debug("begin get_forced_symmetry")
|
763
888
|
if not self.is_full():
|
@@ -1038,6 +1163,13 @@ class Machine(object):
|
|
1038
1163
|
|
1039
1164
|
def sync_with_counterpart(self, cp_machine):
|
1040
1165
|
logger.debug("sync_with_counterpart")
|
1166
|
+
|
1167
|
+
def not_tiny_areas(geom):
|
1168
|
+
sz_list = [a.area_size() for a in geom.list_of_areas()]
|
1169
|
+
max_sz = max(sz_list)
|
1170
|
+
large_sz_list = [sz for sz in sz_list if sz > max_sz * 0.005]
|
1171
|
+
return len(large_sz_list)
|
1172
|
+
|
1041
1173
|
self.geom.sym_counterpart = cp_machine.get_symmetry_part()
|
1042
1174
|
self.geom.sym_part = self.get_symmetry_part()
|
1043
1175
|
logger.debug("part/sym-part: self=%s/%s, cp=%s/%s",
|
@@ -1046,6 +1178,14 @@ class Machine(object):
|
|
1046
1178
|
cp_machine.geom.sym_counterpart = self.get_symmetry_part()
|
1047
1179
|
cp_machine.geom.sym_part = cp_machine.get_symmetry_part()
|
1048
1180
|
|
1181
|
+
if not_tiny_areas(self.geom) == 1:
|
1182
|
+
if not_tiny_areas(cp_machine.geom) > 1:
|
1183
|
+
self.geom.force_to_be_stator()
|
1184
|
+
cp_machine.geom.force_to_be_rotor()
|
1185
|
+
elif not_tiny_areas(cp_machine.geom) == 1:
|
1186
|
+
self.geom.force_to_be_rotor()
|
1187
|
+
cp_machine.geom.force_to_be_stator()
|
1188
|
+
|
1049
1189
|
def search_subregions(self, EESM, single=False):
|
1050
1190
|
logger.debug("Search subregions")
|
1051
1191
|
self.geom.search_subregions(self.startangle,
|
@@ -1070,8 +1210,7 @@ class Machine(object):
|
|
1070
1210
|
|
1071
1211
|
def rebuild_subregions(self, EESM, single=False):
|
1072
1212
|
logger.debug("Rebuild subregions")
|
1073
|
-
self.geom.
|
1074
|
-
self.geom.area_list = []
|
1213
|
+
self.geom.create_list_of_areas(delete=True)
|
1075
1214
|
self.geom.search_subregions(self.startangle,
|
1076
1215
|
self.endangle,
|
1077
1216
|
EESM,
|
@@ -1139,6 +1278,11 @@ class Machine(object):
|
|
1139
1278
|
self.endangle)
|
1140
1279
|
return self.geom.windings_in_the_middle(midangle)
|
1141
1280
|
|
1281
|
+
def has_magnets_in_the_middle(self):
|
1282
|
+
midangle = middle_angle(self.startangle,
|
1283
|
+
self.endangle)
|
1284
|
+
return self.geom.magnets_in_the_middle(midangle)
|
1285
|
+
|
1142
1286
|
def create_mirror_lines_outside_windings(self):
|
1143
1287
|
logger.debug("create_mirror_lines_outside_windings")
|
1144
1288
|
|
@@ -1269,3 +1413,14 @@ class Machine(object):
|
|
1269
1413
|
self.clear_cut_lines()
|
1270
1414
|
self.repair_hull()
|
1271
1415
|
self.set_alfa_and_corners()
|
1416
|
+
|
1417
|
+
def mirror_all_areas(self, mirror_angle):
|
1418
|
+
self.geom.mirror_all_areas(mirror_angle)
|
1419
|
+
|
1420
|
+
def check_airgap_connecting_nodes(self, m_outer):
|
1421
|
+
logger.info("check_airgap_connecting_nodes")
|
1422
|
+
assert(self.geom.is_inner)
|
1423
|
+
assert(m_outer.geom.is_outer)
|
1424
|
+
self.geom.check_airgap_connecting_nodes(m_outer.geom,
|
1425
|
+
self.startangle,
|
1426
|
+
self.endangle)
|
femagtools/dxfsl/shape.py
CHANGED
@@ -11,7 +11,7 @@ from __future__ import print_function
|
|
11
11
|
import numpy as np
|
12
12
|
import logging
|
13
13
|
from .functions import less_equal, greater_equal
|
14
|
-
from .functions import distance, line_m, line_n
|
14
|
+
from .functions import distance, line_m, line_n, mirror_point
|
15
15
|
from .functions import point, points_are_close, points_on_arc
|
16
16
|
from .functions import alpha_line, alpha_angle, alpha_triangle
|
17
17
|
from .functions import normalise_angle, min_angle, max_angle, get_angle_of_arc
|
@@ -54,6 +54,9 @@ class Shape(object):
|
|
54
54
|
def classname(self):
|
55
55
|
return "Shape"
|
56
56
|
|
57
|
+
def clone(self):
|
58
|
+
return None
|
59
|
+
|
57
60
|
def set_my_color(self, color):
|
58
61
|
self.my_color = color
|
59
62
|
|
@@ -314,6 +317,32 @@ class Shape(object):
|
|
314
317
|
def is_near(self, n):
|
315
318
|
return False
|
316
319
|
|
320
|
+
def mirror_shape(self, geom_center, axis_m, axis_n):
|
321
|
+
n2 = mirror_point(self.start(), geom_center, axis_m, axis_n)
|
322
|
+
n1 = mirror_point(self.end(), geom_center, axis_m, axis_n)
|
323
|
+
|
324
|
+
el = None
|
325
|
+
if isinstance(self, Line):
|
326
|
+
el = Line(Element(start=n1, end=n2))
|
327
|
+
|
328
|
+
elif isinstance(self, Arc):
|
329
|
+
c = mirror_point(self.center, geom_center, axis_m, axis_n)
|
330
|
+
alpha1 = alpha_line(c, n1)
|
331
|
+
alpha2 = alpha_line(c, n2)
|
332
|
+
el = Arc(Element(center=c,
|
333
|
+
radius=self.radius,
|
334
|
+
start_angle=alpha1*180/np.pi,
|
335
|
+
end_angle=alpha2*180/np.pi))
|
336
|
+
|
337
|
+
elif isinstance(self, Circle):
|
338
|
+
c = mirror_point(self.center, geom_center, axis_m, axis_n)
|
339
|
+
el = Circle(Element(center=c,
|
340
|
+
radius=self.radius))
|
341
|
+
|
342
|
+
if el:
|
343
|
+
el.copy_attributes(self)
|
344
|
+
return el
|
345
|
+
|
317
346
|
def print_nodes(self):
|
318
347
|
return " n1={}/n2={}".format(self.n1, self.n2)
|
319
348
|
|
@@ -354,6 +383,10 @@ class Circle(Shape):
|
|
354
383
|
def classname(self):
|
355
384
|
return "Circle"
|
356
385
|
|
386
|
+
def clone(self):
|
387
|
+
return Circle(Element(center=self.center,
|
388
|
+
radius=self.radius))
|
389
|
+
|
357
390
|
def render(self, renderer, color='blue', with_nodes=False):
|
358
391
|
tmp_color = self.get_my_color()
|
359
392
|
if not tmp_color:
|
@@ -742,6 +775,14 @@ class Arc(Circle):
|
|
742
775
|
def classname(self):
|
743
776
|
return "Arc"
|
744
777
|
|
778
|
+
def clone(self):
|
779
|
+
alpha_start = alpha_line(self.center, self.p1)
|
780
|
+
alpha_end = alpha_line(self.center, self.p2)
|
781
|
+
return Arc(Element(center=self.center,
|
782
|
+
radius=self.radius,
|
783
|
+
start_angle=alpha_start*180/np.pi,
|
784
|
+
end_angle=alpha_end*180/np.pi))
|
785
|
+
|
745
786
|
def render(self, renderer, color='blue', with_nodes=False):
|
746
787
|
tmp_color = self.get_my_color()
|
747
788
|
if not tmp_color:
|
@@ -1285,6 +1326,10 @@ class Line(Shape):
|
|
1285
1326
|
def classname(self):
|
1286
1327
|
return "Line"
|
1287
1328
|
|
1329
|
+
def clone(self):
|
1330
|
+
return Line(Element(start=self.p1,
|
1331
|
+
end=self.p2))
|
1332
|
+
|
1288
1333
|
def render(self, renderer, color='blue', with_nodes=False):
|
1289
1334
|
tmp_color = self.get_my_color()
|
1290
1335
|
if not tmp_color:
|
femagtools/dxfsl/svgparser.py
CHANGED
@@ -106,7 +106,7 @@ def svgshapes(svgfile):
|
|
106
106
|
for p in svg.findall(".//{http://www.w3.org/2000/svg}path"):
|
107
107
|
m = bcolor.search(p.get('style'))
|
108
108
|
if m:
|
109
|
-
logger.
|
109
|
+
logger.debug("subregion %d: %s", sr, m.groups()[0])
|
110
110
|
yield from get_shapes(p.get('d'))
|
111
111
|
sr += 1
|
112
112
|
for p in svg.findall(".//{http://www.w3.org/2000/svg}line"):
|
femagtools/dxfsl/symmetry.py
CHANGED
@@ -12,6 +12,7 @@ import logging
|
|
12
12
|
import sys
|
13
13
|
from femagtools.dxfsl.shape import Element, Line
|
14
14
|
from femagtools.dxfsl.area import Area
|
15
|
+
import femagtools.dxfsl.area as AREA
|
15
16
|
from femagtools.dxfsl.functions import alpha_angle, positive_angle, is_same_angle
|
16
17
|
from femagtools.dxfsl.functions import min_angle, max_angle, gcd, point
|
17
18
|
from femagtools.dxfsl.functions import less_equal, less, points_are_close
|
@@ -100,24 +101,25 @@ class Symmetry(object):
|
|
100
101
|
return positive_angle(alpha_angle(self.startangle,
|
101
102
|
a.get_mid_angle(self.geom.center)))
|
102
103
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
def area_list_entry(self, a):
|
105
|
+
return (round(a.get_alpha(self.geom.center), 3),
|
106
|
+
round(a.min_dist, 1),
|
107
|
+
round(a.height, 1),
|
108
|
+
self.calc_mid_angle(a),
|
109
|
+
a)
|
109
110
|
|
110
|
-
|
111
|
+
def build_area_list(self, types=()):
|
112
|
+
arealist = self.geom.list_of_areas()
|
113
|
+
if types:
|
114
|
+
arealist = [a for a in arealist if a.type in types]
|
111
115
|
|
112
116
|
areas = []
|
113
117
|
for a in arealist:
|
114
|
-
areas.append((
|
115
|
-
round(a.min_dist, 1),
|
116
|
-
round(a.height, 1),
|
117
|
-
self.calc_mid_angle(a),
|
118
|
-
a))
|
118
|
+
areas.append(self.area_list_entry(a))
|
119
119
|
areas.sort(reverse=True)
|
120
|
+
return areas
|
120
121
|
|
122
|
+
def build_results(self, areas):
|
121
123
|
a0_alpha, a0_min_dist, a0_height, a0_mid_angle, a0 = areas[0]
|
122
124
|
equal_areas = [(a0_mid_angle, a0)]
|
123
125
|
check_rslt = []
|
@@ -146,6 +148,86 @@ class Symmetry(object):
|
|
146
148
|
rslt['area'] = a0
|
147
149
|
rslt['areasize'] = areasize
|
148
150
|
check_rslt.append((areasize, rslt))
|
151
|
+
return check_rslt
|
152
|
+
|
153
|
+
def get_winding_symmetry(self, inside=False):
|
154
|
+
if inside:
|
155
|
+
areas = [self.area_list_entry(a) for a in self.geom.list_of_areas()
|
156
|
+
if not a.close_to_ag]
|
157
|
+
else:
|
158
|
+
areas = self.build_area_list((AREA.TYPE_WINDINGS,))
|
159
|
+
|
160
|
+
logger.debug("begin of Symmetry::get_winding_symmetry: %s areas available", len(areas))
|
161
|
+
if not areas:
|
162
|
+
logger.debug("end of Symmetry::get_winding_symmetry: no areas")
|
163
|
+
return 0
|
164
|
+
|
165
|
+
check_rslt = self.build_results(areas)
|
166
|
+
logger.debug("%s results available", len(check_rslt))
|
167
|
+
[logger.debug("Result: %s", rslt) for rslt in check_rslt]
|
168
|
+
|
169
|
+
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
170
|
+
if parts <= 1:
|
171
|
+
return 0
|
172
|
+
self.create_cut_lines(parts, start_delta)
|
173
|
+
|
174
|
+
sym = self.geom_part * parts
|
175
|
+
delta = 2*np.pi/sym
|
176
|
+
self.set_symmetry_parameters(self.startangle, parts, delta)
|
177
|
+
|
178
|
+
logger.debug("end of Symmetry::get_winding_symmetry: parts=%s", parts)
|
179
|
+
return parts
|
180
|
+
|
181
|
+
def get_magnet_symmetry(self):
|
182
|
+
areas = self.build_area_list((AREA.TYPE_MAGNET_AIRGAP, AREA.TYPE_MAGNET_RECT,))
|
183
|
+
air = self.build_area_list((AREA.TYPE_AIR,))
|
184
|
+
mag_list = [a for a in self.geom.list_of_areas() if a.is_magnet()]
|
185
|
+
air_list = [a for a in self.geom.list_of_areas() if a.is_air()]
|
186
|
+
sz_list = [a.area_size() for a in self.geom.list_of_areas()]
|
187
|
+
max_sz = max(sz_list)
|
188
|
+
for a in air_list:
|
189
|
+
if a.area_size() < max_sz * 0.005:
|
190
|
+
continue
|
191
|
+
for m in mag_list:
|
192
|
+
if a.is_touching(m):
|
193
|
+
areas.append(self.area_list_entry(a))
|
194
|
+
break
|
195
|
+
|
196
|
+
logger.debug("begin of Symmetry::get_magnet_symmetry: %s areas available", len(areas))
|
197
|
+
if not areas:
|
198
|
+
logger.debug("end of Symmetry::get_magnet_symmetry: no areas")
|
199
|
+
return 0
|
200
|
+
|
201
|
+
check_rslt = self.build_results(areas)
|
202
|
+
logger.debug("%s results available", len(check_rslt))
|
203
|
+
[logger.debug("Result: %s", rslt) for rslt in check_rslt]
|
204
|
+
for sz, rslt in check_rslt:
|
205
|
+
if not rslt.get('startdelta', 0.0) == 0.0:
|
206
|
+
return 0 # not proper
|
207
|
+
if rslt.get('halfslice', None):
|
208
|
+
return 0 # not proper
|
209
|
+
|
210
|
+
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
211
|
+
if parts <= 1:
|
212
|
+
return 0
|
213
|
+
self.create_cut_lines(parts, start_delta)
|
214
|
+
|
215
|
+
sym = self.geom_part * parts
|
216
|
+
delta = 2*np.pi/sym
|
217
|
+
self.set_symmetry_parameters(self.startangle, parts, delta)
|
218
|
+
|
219
|
+
logger.debug("end of Symmetry::get_magnet_symmetry: parts=%s", parts)
|
220
|
+
return parts
|
221
|
+
|
222
|
+
def find_symmetry(self):
|
223
|
+
areas = self.build_area_list()
|
224
|
+
|
225
|
+
logger.debug("begin of Symmetry::find_symmetry: %s areas available", len(areas))
|
226
|
+
if not areas:
|
227
|
+
logger.debug("end of Symmetry::find_symmetry: no areas")
|
228
|
+
return 0
|
229
|
+
|
230
|
+
check_rslt = self.build_results(areas)
|
149
231
|
|
150
232
|
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
151
233
|
if parts < 2:
|
@@ -156,18 +238,7 @@ class Symmetry(object):
|
|
156
238
|
self.startangle = self.startangle - self.delta_angle_corr
|
157
239
|
self.endangle = self.endangle - self.delta_angle_corr
|
158
240
|
|
159
|
-
self.
|
160
|
-
for alpha in self.symmetry_lines(parts,
|
161
|
-
self.startangle,
|
162
|
-
start_delta,
|
163
|
-
self.endangle):
|
164
|
-
plus = self.geom.max_radius / 10
|
165
|
-
min_radius = max(10, self.geom.min_radius - plus)
|
166
|
-
p1 = point(self.geom.center, min_radius, alpha)
|
167
|
-
p2 = point(self.geom.center, self.geom.max_radius + plus, alpha)
|
168
|
-
line = Line(Element(start=p1, end=p2))
|
169
|
-
line.init_attributes(color='green')
|
170
|
-
self.geom.add_cut_line(line)
|
241
|
+
self.create_cut_lines(parts, start_delta)
|
171
242
|
|
172
243
|
logger.debug("end of Symmetry::find_symmetry: -> %s", parts)
|
173
244
|
return parts
|
@@ -375,9 +446,6 @@ class Symmetry(object):
|
|
375
446
|
|
376
447
|
dlist = []
|
377
448
|
x = 0
|
378
|
-
# logger.info("inx: %s", inx)
|
379
|
-
# [logger.info("%s deltas: %s", n, d) for n, d in deltas]
|
380
|
-
# [logger.info("area: %s", m) for m, a in area_list]
|
381
449
|
|
382
450
|
for i in inx:
|
383
451
|
for n in range(x, i):
|
@@ -833,6 +901,20 @@ class Symmetry(object):
|
|
833
901
|
logger.debug("return %s parts", parts)
|
834
902
|
return parts
|
835
903
|
|
904
|
+
def create_cut_lines(self, parts, start_delta):
|
905
|
+
self.geom.clear_cut_lines()
|
906
|
+
for alpha in self.symmetry_lines(parts,
|
907
|
+
self.startangle,
|
908
|
+
start_delta,
|
909
|
+
self.endangle):
|
910
|
+
plus = self.geom.max_radius / 10
|
911
|
+
min_radius = max(10, self.geom.min_radius - plus)
|
912
|
+
p1 = point(self.geom.center, min_radius, alpha)
|
913
|
+
p2 = point(self.geom.center, self.geom.max_radius + plus, alpha)
|
914
|
+
line = Line(Element(start=p1, end=p2))
|
915
|
+
line.init_attributes(color='green')
|
916
|
+
self.geom.add_cut_line(line)
|
917
|
+
|
836
918
|
def symmetry_lines(self, parts, startangle, start_delta, endangle):
|
837
919
|
logger.debug("begin symmetry_lines from %s to %s with start %s",
|
838
920
|
startangle,
|
@@ -858,14 +940,17 @@ class Symmetry(object):
|
|
858
940
|
yield start
|
859
941
|
|
860
942
|
# Damit man anschliessend ohne Umstände schneiden kann.
|
861
|
-
self.
|
862
|
-
|
943
|
+
self.set_symmetry_parameters(sym_startangle, parts, delta)
|
944
|
+
logger.debug("end symmetry_lines")
|
945
|
+
|
946
|
+
def set_symmetry_parameters(self, startangle, parts, delta):
|
947
|
+
self.geom.sym_startangle = startangle
|
948
|
+
self.geom.sym_endangle = startangle + delta
|
863
949
|
self.geom.sym_slices = parts
|
864
950
|
self.geom.sym_slice_angle = delta
|
865
951
|
self.geom.sym_area = Area([], (0,0), 0.0)
|
866
952
|
self.geom.sym_area.sym_startangle = self.geom.sym_startangle
|
867
953
|
self.geom.sym_area.sym_endangle = self.geom.sym_endangle
|
868
|
-
logger.debug("end symmetry_lines")
|
869
954
|
|
870
955
|
def check_symmetry_of_mirror(self, mirror_geom, mirrorangle):
|
871
956
|
logger.debug("begin of Symmetry::check_symmetry_of_mirror")
|
femagtools/ecloss.py
CHANGED
@@ -97,7 +97,7 @@ def binterp(x, y, xq, yq, b):
|
|
97
97
|
|
98
98
|
def binterp_ialh2(x, y, xq, yq, b):
|
99
99
|
'''interpolate flux density with Rbf interpolator'''
|
100
|
-
f = RBFInterpolator(np.array([[i, j] for i, j in zip(x, y)]), b)
|
100
|
+
f = RBFInterpolator(np.array([[i, j] for i, j in zip(x, y)]), b, kernel='thin_plate_spline')
|
101
101
|
inp = f(np.array([[i, j] for i, j in zip(xq, yq)]))
|
102
102
|
return inp.reshape(len(np.unique(xq)), -1)
|
103
103
|
|
@@ -571,6 +571,10 @@ class MagnLoss(Amela):
|
|
571
571
|
amplb = np.sqrt(amplbx**2 + amplby**2)
|
572
572
|
fmax2 = 0.5*freq[-1]
|
573
573
|
|
574
|
+
if sum(amplb) == 0:
|
575
|
+
warnings.warn('Bx and By data equals to zero, check simulation parameters for this loadcase')
|
576
|
+
filt = 0
|
577
|
+
|
574
578
|
if sum(amplb) > 0:
|
575
579
|
pec = (np.multiply(amplb,freq))**2
|
576
580
|
pecmax = np.max(pec)
|
@@ -604,10 +608,12 @@ class MagnLoss(Amela):
|
|
604
608
|
|
605
609
|
for ii in range (nx): # Inverse Fourier-Transformation
|
606
610
|
for jj in range (ny):
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
+
sx = np.fft.irfftn(complbx[ii,jj,:], [nt - 1])
|
612
|
+
sy = np.fft.irfftn(complby[ii,jj,:], [nt - 1])
|
613
|
+
sx = np.append(sx, sx[0])
|
614
|
+
sy = np.append(sy, sy[0])
|
615
|
+
sx_pm_3D[ii,jj,:] = sx
|
616
|
+
sy_pm_3D[ii,jj,:] = sy
|
611
617
|
|
612
618
|
return sx_pm_3D, sy_pm_3D
|
613
619
|
|
@@ -736,8 +742,7 @@ class MagnLoss(Amela):
|
|
736
742
|
|
737
743
|
nsegx = max(1,nsegx) # 1 = no segmentation
|
738
744
|
nsegz = max(1,nsegz) # 1 = no segmentation
|
739
|
-
|
740
|
-
nsegy = 1 # y segmentation not supported, nsegy is always = 1
|
745
|
+
nsegy = 1 # y segmentation not supported, nsegy is always = 1
|
741
746
|
|
742
747
|
delta_eff = 0
|
743
748
|
|
@@ -758,7 +763,7 @@ class MagnLoss(Amela):
|
|
758
763
|
(sx_abs, sy_abs, sx_phase, sy_phase, freq_range) = self.Process_B_data(nx, ny, nsegx, nsegy, nt, i['elcp'], i['bl'], excpl_new, eycpl_new)
|
759
764
|
loss = self.loss_ialh2(sx_abs, sy_abs, sx_phase, sy_phase, freq_range, nx, ny, wm, hm, lm, nsegx, nsegy, nsegz, delta_eff) * self.numpoles
|
760
765
|
ialh_loss += loss
|
761
|
-
|
766
|
+
logger.info(f'Loadcase {i["loadcase"]}, Superelement {i["spel_key"]}, Total losses = {loss:.3f} W')
|
762
767
|
loss_detail.append([i['spel_key'], loss/self.numpoles])
|
763
768
|
self.th_loss.append(loss_detail)
|
764
769
|
all_load_cases.append(ialh_loss)
|