femagtools 1.8.16__py3-none-any.whl → 1.8.18__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/airgap.py +5 -1
- femagtools/dxfsl/area.py +52 -23
- femagtools/dxfsl/areabuilder.py +69 -46
- femagtools/dxfsl/converter.py +25 -5
- femagtools/dxfsl/fslrenderer.py +2 -2
- femagtools/dxfsl/geom.py +264 -68
- femagtools/dxfsl/machine.py +38 -8
- femagtools/dxfsl/symmetry.py +20 -5
- femagtools/femag.py +27 -16
- femagtools/machine/__init__.py +2 -0
- femagtools/machine/effloss.py +10 -4
- femagtools/machine/pm.py +72 -68
- femagtools/machine/sm.py +15 -15
- femagtools/plot/bch.py +3 -1
- femagtools/plot/char.py +5 -16
- femagtools/plot/nc.py +67 -34
- femagtools/shortcircuit.py +10 -3
- femagtools/utils.py +5 -4
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/METADATA +2 -2
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/RECORD +26 -26
- tests/test_machine.py +1 -2
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/WHEEL +0 -0
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/licenses/LICENSE +0 -0
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/geom.py
CHANGED
@@ -35,7 +35,7 @@ from .functions import middle_angle, positive_angle
|
|
35
35
|
from .functions import normalise_angle, is_same_angle
|
36
36
|
from .functions import part_of_circle, gcd
|
37
37
|
from .functions import point_on_arc, points_on_line, nodes_are_equal
|
38
|
-
from .functions import area_size
|
38
|
+
from .functions import area_size, get_angle_of_arc
|
39
39
|
import io
|
40
40
|
import time
|
41
41
|
|
@@ -401,11 +401,11 @@ class Geometry(object):
|
|
401
401
|
for n in self.g.nodes()}
|
402
402
|
nx.relabel_nodes(self.g, mapping, copy=False)
|
403
403
|
|
404
|
-
def
|
404
|
+
def get_rotated_nodes(self, alpha, nodes):
|
405
405
|
T = np.array(((np.cos(alpha), -np.sin(alpha)),
|
406
406
|
(np.sin(alpha), np.cos(alpha))))
|
407
|
-
|
408
|
-
return
|
407
|
+
nodes = [T.dot(np.array((n[0], n[1]))).tolist() for n in nodes]
|
408
|
+
return nodes
|
409
409
|
|
410
410
|
def rotate(self, alpha):
|
411
411
|
"""rotates all objects by angle alpha"""
|
@@ -1142,20 +1142,30 @@ class Geometry(object):
|
|
1142
1142
|
rtol=self.rtol,
|
1143
1143
|
atol=self.atol)
|
1144
1144
|
|
1145
|
-
def get_corner_nodes(self, center, angle):
|
1146
|
-
rtol = 1e-4
|
1147
|
-
atol = 1e-4
|
1148
|
-
|
1145
|
+
def get_corner_nodes(self, center, angle, rtol=1e-4, atol=1e-4):
|
1149
1146
|
center_added, corners = self.get_corner_list(center, angle, rtol, atol)
|
1150
1147
|
if len(corners) < 2:
|
1151
1148
|
return () # not enough corners
|
1152
1149
|
return (corners[0].point(), corners[len(corners)-1].point())
|
1153
1150
|
|
1154
|
-
def set_start_corners(self, center, angle):
|
1155
|
-
self.start_corners = self.get_corner_nodes(center, angle)
|
1151
|
+
def set_start_corners(self, center, angle, rtol=1e-4, atol=1e-4):
|
1152
|
+
self.start_corners = self.get_corner_nodes(center, angle, rtol=rtol, atol=atol)
|
1156
1153
|
|
1157
|
-
def set_end_corners(self, center, angle):
|
1158
|
-
self.end_corners = self.get_corner_nodes(center, angle)
|
1154
|
+
def set_end_corners(self, center, angle, rtol=1e-4, atol=1e-4):
|
1155
|
+
self.end_corners = self.get_corner_nodes(center, angle, rtol=rtol, atol=atol)
|
1156
|
+
|
1157
|
+
def set_virtual_start_end_corners(self):
|
1158
|
+
assert(not self.start_corners)
|
1159
|
+
assert(not self.end_corners)
|
1160
|
+
|
1161
|
+
dist_list = [(distance(self.center, n), n) for n in self.nodes()]
|
1162
|
+
dist_list.sort()
|
1163
|
+
d1, c1 = dist_list[0]
|
1164
|
+
d2, c2 = dist_list[-1]
|
1165
|
+
corners = (c1, c2)
|
1166
|
+
self.start_corners = corners
|
1167
|
+
self.end_corners = corners
|
1168
|
+
return
|
1159
1169
|
|
1160
1170
|
def get_angle(self, alpha1, alpha2):
|
1161
1171
|
if np.isclose(alpha1, alpha2, 0.001, 0.001):
|
@@ -1904,6 +1914,19 @@ class Geometry(object):
|
|
1904
1914
|
self.area_list = []
|
1905
1915
|
return nodes_deleted > 0
|
1906
1916
|
|
1917
|
+
def delete_needless_elements(self, radius):
|
1918
|
+
self.area_list = []
|
1919
|
+
for e in self.elements():
|
1920
|
+
if greater(distance(self.center, e.p1), radius):
|
1921
|
+
self.remove_edge(e)
|
1922
|
+
elif greater(distance(self.center, e.p2), radius):
|
1923
|
+
self.remove_edge(e)
|
1924
|
+
elif is_Arc(e):
|
1925
|
+
p = e.center_of_connection()
|
1926
|
+
if greater(distance(self.center, p), radius):
|
1927
|
+
self.remove_edge(e)
|
1928
|
+
self.delete_all_appendices()
|
1929
|
+
|
1907
1930
|
def render_areagroups(self, renderer):
|
1908
1931
|
if not self.areagroup_list:
|
1909
1932
|
return
|
@@ -2036,11 +2059,47 @@ class Geometry(object):
|
|
2036
2059
|
return c
|
2037
2060
|
return None
|
2038
2061
|
|
2062
|
+
def check_hull_radius(self, center, radius, hull_points):
|
2063
|
+
logger.debug("check_hull_radius")
|
2064
|
+
min_r = radius
|
2065
|
+
max_r = radius
|
2066
|
+
for p in hull_points:
|
2067
|
+
d = round(distance(center, p), 2)
|
2068
|
+
min_r = min(min_r, d)
|
2069
|
+
max_r = max(max_r, d)
|
2070
|
+
|
2071
|
+
if min_r > radius * 0.8:
|
2072
|
+
# radius is ok, adjust hill line
|
2073
|
+
return True, max_r > radius
|
2074
|
+
|
2075
|
+
return False, False
|
2076
|
+
|
2039
2077
|
def get_machine_part(self, mm):
|
2040
2078
|
logger.debug("*** Begin of get_machine_part() ***")
|
2041
2079
|
|
2042
2080
|
h_points = [h for h in convex_hull(self.virtual_nodes())]
|
2043
|
-
center = self.
|
2081
|
+
center, radius = self.get_center_arcs(mm)
|
2082
|
+
if center and radius:
|
2083
|
+
center_left = round(center[0] - mm[0], 4)
|
2084
|
+
center_right = round(mm[1] - center[0], 4)
|
2085
|
+
center_down = round(center[1] - mm[2], 4)
|
2086
|
+
center_up = round(mm[3] - center[1], 4)
|
2087
|
+
min_r = min(center_left, center_right, center_up, center_down)
|
2088
|
+
max_r = max(center_left, center_right, center_up, center_down)
|
2089
|
+
is_full = min_r > max_r / 2
|
2090
|
+
|
2091
|
+
ok, adjust_hull = self.check_hull_radius(center, radius, h_points)
|
2092
|
+
if is_full and ok:
|
2093
|
+
self.set_center([round(center[0], 8), round(center[1], 8)])
|
2094
|
+
self.area_list = []
|
2095
|
+
machine = Machine(self,
|
2096
|
+
radius=radius,
|
2097
|
+
startangle=0.0,
|
2098
|
+
endangle=0.0)
|
2099
|
+
return machine
|
2100
|
+
|
2101
|
+
center = self.get_center(center, h_points, mm)
|
2102
|
+
|
2044
2103
|
logger.debug(" - Center is %s", center)
|
2045
2104
|
|
2046
2105
|
min_radius = 99999
|
@@ -2259,9 +2318,14 @@ class Geometry(object):
|
|
2259
2318
|
def is_same_center(self, center_lst, center, rtol, atol):
|
2260
2319
|
for c in center_lst:
|
2261
2320
|
if points_are_close(c['center'], center['center'], rtol, atol):
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2321
|
+
new_radius, new_phi = center['radiuslist'][0]
|
2322
|
+
c_radiuslist = [r for r, p in c['radiuslist']]
|
2323
|
+
try:
|
2324
|
+
i = c_radiuslist.index(new_radius)
|
2325
|
+
c_radius, c_phi = c['radiuslist'][i]
|
2326
|
+
c['radiuslist'][i][1] = c_phi + new_phi
|
2327
|
+
except:
|
2328
|
+
c['radiuslist'].append([new_radius, new_phi])
|
2265
2329
|
c['count'] = c['count'] + 1
|
2266
2330
|
return True
|
2267
2331
|
return False
|
@@ -2283,7 +2347,6 @@ class Geometry(object):
|
|
2283
2347
|
return None
|
2284
2348
|
cy_list = [(c['center'][0], c) for c in c_list]
|
2285
2349
|
cy_list.sort()
|
2286
|
-
[logger.info("y=%s, c=%s", y, c) for y, c in cy_list]
|
2287
2350
|
y, c = cy_list[0]
|
2288
2351
|
return c
|
2289
2352
|
|
@@ -2302,14 +2365,23 @@ class Geometry(object):
|
|
2302
2365
|
return True
|
2303
2366
|
return False
|
2304
2367
|
|
2368
|
+
def get_best_radius(radiuslist):
|
2369
|
+
radiuslist.sort(reverse=True)
|
2370
|
+
r1, phi1 = radiuslist[0]
|
2371
|
+
for r2, phi2 in radiuslist[1:]:
|
2372
|
+
if phi2 > phi1:
|
2373
|
+
return r2
|
2374
|
+
break
|
2375
|
+
return r1
|
2376
|
+
|
2305
2377
|
circles = [e for e in self.elements() if is_Circle(e)]
|
2306
2378
|
logger.debug(" -- %s Circles", len(circles))
|
2307
2379
|
|
2308
2380
|
for e in circles:
|
2309
2381
|
center = (round(e.center[0], 3), round(e.center[1], 3))
|
2382
|
+
angle = e.get_angle_of_arc()
|
2310
2383
|
entry = {'center': center,
|
2311
|
-
'
|
2312
|
-
'phi': e.get_angle_of_arc(),
|
2384
|
+
'radiuslist': [[round(e.radius, 1), angle]],
|
2313
2385
|
'dist': e.length(),
|
2314
2386
|
'inside': center_is_inside(center),
|
2315
2387
|
'count': 1}
|
@@ -2320,9 +2392,9 @@ class Geometry(object):
|
|
2320
2392
|
|
2321
2393
|
for e in arcs:
|
2322
2394
|
center = (round(e.center[0], 3), round(e.center[1], 3))
|
2395
|
+
angle = e.get_angle_of_arc()
|
2323
2396
|
entry = {'center': center,
|
2324
|
-
'
|
2325
|
-
'phi': e.get_angle_of_arc(),
|
2397
|
+
'radiuslist': [[round(e.radius, 1), angle]],
|
2326
2398
|
'dist': e.length(),
|
2327
2399
|
'inside': center_is_inside(center),
|
2328
2400
|
'count': 1}
|
@@ -2330,7 +2402,7 @@ class Geometry(object):
|
|
2330
2402
|
center_list.append(entry)
|
2331
2403
|
|
2332
2404
|
center = None
|
2333
|
-
arc_list = [[c['count'], len(c['
|
2405
|
+
arc_list = [[c['count'], len(c['radiuslist']), n, c]
|
2334
2406
|
for n, c in enumerate(center_list)]
|
2335
2407
|
arc_list.sort(reverse=True)
|
2336
2408
|
|
@@ -2340,63 +2412,63 @@ class Geometry(object):
|
|
2340
2412
|
[logger.debug("Arc %s", arc) for arc in arc_list]
|
2341
2413
|
if not arc_list:
|
2342
2414
|
logger.debug("end of get_center_arcs: no arcs")
|
2343
|
-
return None
|
2415
|
+
return None, 0
|
2344
2416
|
|
2345
|
-
cnt, cr1,
|
2417
|
+
cnt, cr1, n, c1 = arc_list[0]
|
2346
2418
|
logger.debug("First Entry: %s", c1)
|
2347
2419
|
center = c1['center']
|
2420
|
+
radius = get_best_radius(c1['radiuslist'])
|
2348
2421
|
if len(arc_list) > 1:
|
2349
|
-
cnt, cr2,
|
2422
|
+
cnt, cr2, n, c2 = arc_list[1]
|
2350
2423
|
logger.debug("Second Entry: %s", c2)
|
2351
2424
|
if not cr1 > cr2:
|
2352
2425
|
center = None
|
2353
2426
|
|
2354
2427
|
if center:
|
2355
|
-
logger.debug("end of get_center_arcs:
|
2356
|
-
return center
|
2428
|
+
logger.debug("end of get_center_arcs: c=%s, r=%s", center, radius)
|
2429
|
+
return center, radius
|
2357
2430
|
|
2358
2431
|
c_entry = self.get_center_with_x(center_list, x_min)
|
2359
2432
|
if c_entry:
|
2360
2433
|
center = c_entry['center']
|
2361
2434
|
if center[1] < y_min:
|
2362
|
-
logger.debug("end of get_center_arcs
|
2363
|
-
return center
|
2435
|
+
logger.debug("end of get_center_arcs (x): c=%s", center)
|
2436
|
+
return center, 0
|
2437
|
+
|
2364
2438
|
c_entry = self.get_center_with_y(center_list, y_min)
|
2365
2439
|
if c_entry:
|
2366
2440
|
center = c_entry['center']
|
2367
2441
|
if center[0] < x_min:
|
2368
|
-
logger.debug("end of get_center_arcs
|
2369
|
-
return center
|
2442
|
+
logger.debug("end of get_center_arcs (y): c=%s", center)
|
2443
|
+
return center, 0
|
2370
2444
|
|
2371
2445
|
logger.debug("end of get_center_arcs: no center found")
|
2372
|
-
return None
|
2446
|
+
return None, 0
|
2373
2447
|
|
2374
2448
|
def get_center_dim(self, mm):
|
2375
2449
|
return (round(mm[0], 4), round(mm[2], 4))
|
2376
2450
|
|
2377
|
-
def get_center(self,
|
2378
|
-
logger.debug("Begin of get_center(%s points)", len(
|
2379
|
-
if len(
|
2451
|
+
def get_center(self, center_arcs, hull_points, mm):
|
2452
|
+
logger.debug("Begin of get_center(%s hull-points)", len(hull_points))
|
2453
|
+
if len(hull_points) < 3:
|
2380
2454
|
return None
|
2381
2455
|
|
2382
2456
|
center = None
|
2383
2457
|
# Zuerst suchen wir anhand der Circle- und Arc-Segmente nach einem
|
2384
2458
|
# möglichen Center-Punkt.
|
2385
|
-
center_arcs = self.get_center_arcs(mm)
|
2386
|
-
|
2387
2459
|
if center_arcs:
|
2388
2460
|
center = center_arcs
|
2389
2461
|
else:
|
2390
2462
|
# Wir finden keine Arc-Objekte, welche uns einen Hinweis auf den
|
2391
2463
|
# Center geben können. Wir versuchen in der Verzweiflung mit
|
2392
2464
|
# center_hull oder x(min) und y(min)
|
2393
|
-
center_hull = self.get_center_hull(
|
2465
|
+
center_hull = self.get_center_hull(_hull_points)
|
2394
2466
|
if center_hull:
|
2395
2467
|
center = center_hull
|
2396
2468
|
else:
|
2397
2469
|
center = self.get_center_dim(mm)
|
2398
2470
|
|
2399
|
-
center_xaxis = self.get_center_xaxis(
|
2471
|
+
center_xaxis = self.get_center_xaxis(hull_points)
|
2400
2472
|
y = center_xaxis[1]
|
2401
2473
|
if y is not None:
|
2402
2474
|
if np.isclose(y, center[1], atol=0.3):
|
@@ -2612,6 +2684,7 @@ class Geometry(object):
|
|
2612
2684
|
areas_inside = [a for a in self.area_list
|
2613
2685
|
if area.is_inside(a, self)]
|
2614
2686
|
if not areas_inside:
|
2687
|
+
area.areas_inside = {}
|
2615
2688
|
continue
|
2616
2689
|
|
2617
2690
|
areas_notouch = {a.identifier(): a for a in areas_inside
|
@@ -3748,6 +3821,69 @@ class Geometry(object):
|
|
3748
3821
|
|
3749
3822
|
logger.debug("end of search_unknown_subregions")
|
3750
3823
|
|
3824
|
+
def possible_magnet_in_the_middle(self, midangle):
|
3825
|
+
self.set_areas_inside_for_all_areas()
|
3826
|
+
mags = []
|
3827
|
+
for n, a in enumerate(self.list_of_areas()):
|
3828
|
+
if a.areas_inside:
|
3829
|
+
continue
|
3830
|
+
if a.close_to_startangle or a.close_to_endangle:
|
3831
|
+
continue
|
3832
|
+
if np.isclose(a.min_dist, self.min_radius):
|
3833
|
+
continue
|
3834
|
+
if np.isclose(a.max_dist, self.max_radius):
|
3835
|
+
continue
|
3836
|
+
|
3837
|
+
a_midangle = a.get_mid_angle(self.center)
|
3838
|
+
if np.isclose(midangle, a_midangle, atol=1e-2, rtol=1e-2):
|
3839
|
+
s = a.area_size()
|
3840
|
+
mags.append([s, n, a, a_midangle])
|
3841
|
+
|
3842
|
+
if not mags:
|
3843
|
+
logger.debug("possible_magnet_in_the_middle: No Areas for Magnets")
|
3844
|
+
return None
|
3845
|
+
|
3846
|
+
mags.sort(reverse=True)
|
3847
|
+
to_angle = np.pi / 2
|
3848
|
+
for s, n, a, mid in mags:
|
3849
|
+
angle = to_angle - mid
|
3850
|
+
nodelist = a.list_of_nodes()
|
3851
|
+
nodes = self.get_rotated_nodes(angle, nodelist)
|
3852
|
+
p1 = self.center
|
3853
|
+
p2 = point(self.center, self.max_radius + 10, mid)
|
3854
|
+
line = Line(Element(start=p1, end=p2))
|
3855
|
+
nodelist = a.get_intersect_points(line)
|
3856
|
+
mid_nodes = self.get_rotated_nodes(angle, nodelist)
|
3857
|
+
if self.is_possible_magnet(nodes, mid_nodes):
|
3858
|
+
a.set_type(AREA.TYPE_MAGNET_AIRGAP)
|
3859
|
+
a.phi = mid
|
3860
|
+
a.mag_width = (a.max_dist - a.min_dist) * 0.9
|
3861
|
+
return a
|
3862
|
+
|
3863
|
+
logger.debug("possible_magnet_in_the_middle: No Magnets")
|
3864
|
+
return None
|
3865
|
+
|
3866
|
+
def is_possible_magnet(self, all_nodes, mid_nodes):
|
3867
|
+
all_y = [n[1] for n in all_nodes]
|
3868
|
+
all_y.sort()
|
3869
|
+
mid_y = [n[1] for n in mid_nodes]
|
3870
|
+
mid_y.sort()
|
3871
|
+
|
3872
|
+
logger.debug("is_possible_magnet: mid y min/max = %s/%s", mid_y[0], mid_y[-1])
|
3873
|
+
logger.debug("is_possible_magnet: all y min/max = %s/%s", all_y[0], all_y[-1])
|
3874
|
+
|
3875
|
+
if all_y[0] > mid_y[-1]:
|
3876
|
+
return False
|
3877
|
+
return True
|
3878
|
+
|
3879
|
+
def force_area_as_magnet(self, area):
|
3880
|
+
for a in self.list_of_areas():
|
3881
|
+
if a.is_equal(area, 1e-2):
|
3882
|
+
a.set_type(area.type)
|
3883
|
+
a.phi = area.phi
|
3884
|
+
a.mag_width = area.mag_width
|
3885
|
+
return
|
3886
|
+
|
3751
3887
|
def magnets_in_the_middle(self, midangle):
|
3752
3888
|
mag_areas = [a for a in self.list_of_areas()
|
3753
3889
|
if a.is_magnet()]
|
@@ -3768,16 +3904,20 @@ class Geometry(object):
|
|
3768
3904
|
return False
|
3769
3905
|
|
3770
3906
|
def looking_for_corners(self):
|
3771
|
-
|
3772
|
-
|
3773
|
-
|
3774
|
-
|
3775
|
-
|
3776
|
-
|
3777
|
-
|
3778
|
-
|
3779
|
-
|
3780
|
-
|
3907
|
+
try:
|
3908
|
+
if self.is_inner:
|
3909
|
+
logger.debug("looking_for_corners: inner")
|
3910
|
+
start_cp = self.start_corners[-1]
|
3911
|
+
end_cp = self.end_corners[-1]
|
3912
|
+
else:
|
3913
|
+
logger.debug("looking_for_corners: outer")
|
3914
|
+
start_cp = self.start_corners[0]
|
3915
|
+
end_cp = self.end_corners[0]
|
3916
|
+
logger.debug("looking_for_corners: start=%s, end=%s",
|
3917
|
+
start_cp, end_cp)
|
3918
|
+
except IndexError:
|
3919
|
+
return
|
3920
|
+
|
3781
3921
|
for area in self.list_of_areas():
|
3782
3922
|
area.mark_airgap_corners(start_cp, end_cp)
|
3783
3923
|
return
|
@@ -4188,28 +4328,11 @@ class Geometry(object):
|
|
4188
4328
|
return True
|
4189
4329
|
return False
|
4190
4330
|
|
4191
|
-
def _line_inside_magnets(self, p1, p2):
|
4192
|
-
for area in self.list_of_areas():
|
4193
|
-
if area.is_magnet():
|
4194
|
-
if area.is_point_inside(p1):
|
4195
|
-
if area.is_point_inside(p2):
|
4196
|
-
return True
|
4197
|
-
return False
|
4198
|
-
|
4199
|
-
def _line_inside_air(self, p1, p2):
|
4200
|
-
for area in self.list_of_areas():
|
4201
|
-
if area.is_air():
|
4202
|
-
if area.is_point_inside(p1):
|
4203
|
-
if area.is_point_inside(p2):
|
4204
|
-
return True
|
4205
|
-
return False
|
4206
|
-
|
4207
4331
|
def _line_inside_not_iron(self, p1, p2):
|
4208
4332
|
for area in self.list_of_areas():
|
4209
4333
|
if area.is_shaft() or area.is_air() or area.is_magnet():
|
4210
|
-
if area.
|
4211
|
-
|
4212
|
-
return True
|
4334
|
+
if area.is_line_inside(p1, p2):
|
4335
|
+
return True
|
4213
4336
|
return False
|
4214
4337
|
|
4215
4338
|
def inside_area_list(self, p):
|
@@ -4301,6 +4424,73 @@ class Geometry(object):
|
|
4301
4424
|
builder = AreaBuilder(geom=self)
|
4302
4425
|
return builder.create_inner_corner_auxiliary_areas(startangle, endangle)
|
4303
4426
|
|
4427
|
+
def analyse_airgap_line(self, inner):
|
4428
|
+
if inner: # TODO
|
4429
|
+
return False
|
4430
|
+
|
4431
|
+
areas = self.list_of_areas()
|
4432
|
+
builder = AreaBuilder(geom=self)
|
4433
|
+
ag_nodes, ag_el = builder.get_outer_airgap_line()
|
4434
|
+
if not ag_nodes:
|
4435
|
+
logger.warning("Fatal: No nodes found")
|
4436
|
+
return False
|
4437
|
+
|
4438
|
+
distlist = [distance(self.center, n) for n in ag_nodes]
|
4439
|
+
min_dist = min(distlist)
|
4440
|
+
max_dist = max(distlist)
|
4441
|
+
logger.debug("Airgap min/max from center: %s/%s", min_dist, max_dist)
|
4442
|
+
for a in areas:
|
4443
|
+
logger.debug("%s: min/max from center: %s/%s", a.identifier(), a.min_dist, a.max_dist)
|
4444
|
+
logger.debug("%s: min/max x: %s/%s, y: %s/%s",
|
4445
|
+
a.identifier(),
|
4446
|
+
a.min_x, a.max_x,
|
4447
|
+
a.min_y, a.max_y)
|
4448
|
+
if less_equal(a.min_x, -min_dist) and greater_equal(a.max_x, min_dist) and \
|
4449
|
+
less_equal(a.min_y, -min_dist) and greater_equal(a.max_y, min_dist):
|
4450
|
+
logger.debug("%s: around center", a.identifier())
|
4451
|
+
continue
|
4452
|
+
if np.isclose(a.min_dist, min_dist, rtol=1e-3, atol=1e-2):
|
4453
|
+
continue
|
4454
|
+
if less_equal(a.max_dist, max_dist, rtol=1e-3, atol=1e-2):
|
4455
|
+
return False
|
4456
|
+
|
4457
|
+
return builder.close_outer_winding_areas()
|
4458
|
+
|
4459
|
+
def adjust_outer_hull_for_symmetry(self):
|
4460
|
+
logger.debug("adjust_outer_hull_for_symmetry()")
|
4461
|
+
areas = self.list_of_areas()
|
4462
|
+
builder = AreaBuilder(geom=self)
|
4463
|
+
op_nodes, op_el = builder.get_outer_opposite_airgap_line()
|
4464
|
+
if not op_nodes:
|
4465
|
+
logger.warning("Fatal: No nodes found")
|
4466
|
+
return False
|
4467
|
+
|
4468
|
+
radiuslist = {}
|
4469
|
+
n1 = op_nodes[0]
|
4470
|
+
d1 = distance(self.center, n1)
|
4471
|
+
a1 = alpha_line(self.center, n1)
|
4472
|
+
for n2 in op_nodes[1:]:
|
4473
|
+
d2 = distance(self.center, n2)
|
4474
|
+
a2 = alpha_line(self.center, n2)
|
4475
|
+
if np.isclose(d1, d2, rtol=1e-3, atol=1e-2):
|
4476
|
+
r = round((d1 + d2) / 2, 1)
|
4477
|
+
alpha = get_angle_of_arc(a2, a1)
|
4478
|
+
radius_alpha = radiuslist.get(r, 0.0) + alpha
|
4479
|
+
radiuslist[r] = radius_alpha
|
4480
|
+
|
4481
|
+
n1 = n2
|
4482
|
+
d1 = d2
|
4483
|
+
a1 = a2
|
4484
|
+
|
4485
|
+
rlist = [(radiuslist[r], r) for r in radiuslist]
|
4486
|
+
rlist.sort(reverse=True)
|
4487
|
+
alpha, best_radius = rlist[0]
|
4488
|
+
if np.isclose(best_radius, self.max_radius, rtol=1e-3, atol=1e-2):
|
4489
|
+
return False
|
4490
|
+
logger.debug("Best Outer Radius is %s", best_radius)
|
4491
|
+
self.adjust_outer_hull(best_radius)
|
4492
|
+
return True
|
4493
|
+
|
4304
4494
|
def close_outer_winding_areas(self):
|
4305
4495
|
logger.debug("begin close_outer_winding_areas(%s areas)",
|
4306
4496
|
len(self.area_list))
|
@@ -4622,3 +4812,9 @@ class Geometry(object):
|
|
4622
4812
|
|
4623
4813
|
with io.open(name, 'w', encoding='utf-8') as f:
|
4624
4814
|
f.write('\n'.join(content))
|
4815
|
+
|
4816
|
+
def adjust_outer_hull(self, new_radius):
|
4817
|
+
c = Circle(Element(center=self.center, radius=new_radius))
|
4818
|
+
self.add_element(c, 1e-3, 1e-3)
|
4819
|
+
self.delete_needless_elements(new_radius)
|
4820
|
+
self.max_radius = new_radius
|
femagtools/dxfsl/machine.py
CHANGED
@@ -580,10 +580,8 @@ class Machine(object):
|
|
580
580
|
return self.geom.create_auxiliary_lines(self.startangle, self.endangle)
|
581
581
|
|
582
582
|
def set_alfa_and_corners(self):
|
583
|
-
self.geom.
|
584
|
-
|
585
|
-
self.geom.end_corners = self.geom.get_corner_nodes(self.center,
|
586
|
-
self.endangle)
|
583
|
+
self.geom.set_start_corners(self.center, self.startangle)
|
584
|
+
self.geom.set_end_corners(self.center, self.endangle)
|
587
585
|
self.geom.alfa = alpha_angle(self.startangle, self.endangle)
|
588
586
|
|
589
587
|
if self.mirror_geom is not None:
|
@@ -639,6 +637,22 @@ class Machine(object):
|
|
639
637
|
if self.radius <= 0.0:
|
640
638
|
return False
|
641
639
|
|
640
|
+
if is_outer:
|
641
|
+
self.geom.set_subregion_parameters(self.startangle, self.endangle)
|
642
|
+
if self.part > 1:
|
643
|
+
self.geom.set_start_corners(self.center, self.startangle, rtol=1e-3, atol=1e-2)
|
644
|
+
self.geom.set_end_corners(self.center, self.endangle, rtol=1e-3, atol=1e-2)
|
645
|
+
else:
|
646
|
+
self.geom.set_virtual_start_end_corners()
|
647
|
+
|
648
|
+
self.geom.looking_for_corners()
|
649
|
+
create_areas = self.geom.analyse_airgap_line(is_inner)
|
650
|
+
if self.geom.adjust_outer_hull_for_symmetry():
|
651
|
+
create_areas = True
|
652
|
+
|
653
|
+
if create_areas:
|
654
|
+
self.geom.create_list_of_areas(delete=True)
|
655
|
+
|
642
656
|
symmetry = Symmetry(geom=self.geom,
|
643
657
|
startangle=self.startangle,
|
644
658
|
endangle=self.endangle)
|
@@ -1259,6 +1273,11 @@ class Machine(object):
|
|
1259
1273
|
def has_magnets(self):
|
1260
1274
|
return self.geom.has_magnets
|
1261
1275
|
|
1276
|
+
def magnets_missing(self, EESM):
|
1277
|
+
if EESM:
|
1278
|
+
return False
|
1279
|
+
return not self.has_magnets()
|
1280
|
+
|
1262
1281
|
def delete_tiny_elements(self, mindist):
|
1263
1282
|
return self.geom.delete_tiny_elements(mindist)
|
1264
1283
|
|
@@ -1320,6 +1339,11 @@ class Machine(object):
|
|
1320
1339
|
self.endangle)
|
1321
1340
|
return self.geom.magnets_in_the_middle(midangle)
|
1322
1341
|
|
1342
|
+
def looking_for_one_possible_magnet(self):
|
1343
|
+
midangle = middle_angle(self.startangle,
|
1344
|
+
self.endangle)
|
1345
|
+
return self.geom.possible_magnet_in_the_middle(midangle)
|
1346
|
+
|
1323
1347
|
def create_mirror_lines_outside_windings(self):
|
1324
1348
|
logger.debug("create_mirror_lines_outside_windings")
|
1325
1349
|
|
@@ -1343,10 +1367,11 @@ class Machine(object):
|
|
1343
1367
|
pts = self.geom.split_and_get_intersect_points(line, aktion=False)
|
1344
1368
|
pts.sort()
|
1345
1369
|
|
1370
|
+
arcs_created = False
|
1346
1371
|
p_critical = self.geom.critical_touch_point(pts)
|
1347
1372
|
if p_critical:
|
1348
1373
|
d_critical = distance(self.center, p_critical)
|
1349
|
-
logger.
|
1374
|
+
logger.debug("Critical Point: %s, len=%s", p_critical, d_critical)
|
1350
1375
|
sep_radius = self.get_iron_separator(radius_list)
|
1351
1376
|
logger.debug("Iron Separator found: %s", sep_radius)
|
1352
1377
|
if sep_radius > 0.0 and sep_radius < d_critical:
|
@@ -1357,8 +1382,15 @@ class Machine(object):
|
|
1357
1382
|
if r[1] < d_critical:
|
1358
1383
|
if self.create_arc(r[1]):
|
1359
1384
|
radius = r[1]
|
1385
|
+
arcs_created = True
|
1360
1386
|
break
|
1361
1387
|
|
1388
|
+
if arcs_created:
|
1389
|
+
self.geom.create_list_of_areas(delete=True)
|
1390
|
+
self.geom.search_subregions(self.startangle,
|
1391
|
+
self.endangle,
|
1392
|
+
False)
|
1393
|
+
|
1362
1394
|
# install line
|
1363
1395
|
line = Line(
|
1364
1396
|
Element(start=self.center,
|
@@ -1366,11 +1398,9 @@ class Machine(object):
|
|
1366
1398
|
|
1367
1399
|
pts = self.geom.split_and_get_intersect_points(line)
|
1368
1400
|
pts.sort()
|
1369
|
-
|
1370
1401
|
if self.geom.create_lines_outside_windings(pts):
|
1371
|
-
self.geom.area_list = []
|
1372
1402
|
logger.debug("create subregions again")
|
1373
|
-
self.geom.create_list_of_areas()
|
1403
|
+
self.geom.create_list_of_areas(delete=True)
|
1374
1404
|
self.geom.search_subregions(self.startangle,
|
1375
1405
|
self.endangle,
|
1376
1406
|
False)
|
femagtools/dxfsl/symmetry.py
CHANGED
@@ -48,6 +48,7 @@ class Symmetry(object):
|
|
48
48
|
self.atol = atol
|
49
49
|
self.full = False
|
50
50
|
self.ag_radius = 0.0
|
51
|
+
self.height = geom.max_radius - geom.min_radius
|
51
52
|
if np.isclose(self.startangle, self.endangle):
|
52
53
|
self.alpha = 2.0*np.pi
|
53
54
|
self.full = True
|
@@ -120,9 +121,6 @@ class Symmetry(object):
|
|
120
121
|
areas.sort(reverse=True)
|
121
122
|
return areas
|
122
123
|
|
123
|
-
def get_equal_areas(self, areas):
|
124
|
-
return
|
125
|
-
|
126
124
|
def build_results(self, areas):
|
127
125
|
logger.debug("begin of build_results with %s areas", len(areas))
|
128
126
|
[logger.debug("#%s: alpha=%s, min=%s, max=%s",
|
@@ -286,13 +284,22 @@ class Symmetry(object):
|
|
286
284
|
logger.debug("Geometry: Alpha=%s, Center=%s", self.alpha, self.geom.center)
|
287
285
|
mid_angle, a = area_list[0]
|
288
286
|
result['height'] = a.height
|
287
|
+
result['min_dist'] = a.min_dist
|
288
|
+
result['max_dist'] = a.max_dist
|
289
289
|
result['alpha'] = a.get_alpha(self.geom.center)
|
290
290
|
if self.geom.is_inner:
|
291
291
|
result['airgap'] = np.isclose(a.max_dist, self.ag_radius)
|
292
292
|
else:
|
293
293
|
result['airgap'] = np.isclose(a.min_dist, self.ag_radius)
|
294
|
+
upper_quarter = self.geom.min_radius + self.height * 0.75
|
295
|
+
upper_half = self.geom.min_radius + self.height * 0.5
|
296
|
+
if a.max_dist > upper_quarter:
|
297
|
+
if a.min_dist > upper_half:
|
298
|
+
result['upper_quarter'] = True
|
294
299
|
if len(area_list) == 1: # one area
|
295
|
-
|
300
|
+
rslt = self.check_one_area(mid_angle, a, result, rtol=rtol, atol=atol)
|
301
|
+
logger.debug("end of check_delta")
|
302
|
+
return rslt
|
296
303
|
|
297
304
|
self.delta_check_count += 1
|
298
305
|
area_list.sort()
|
@@ -353,6 +360,7 @@ class Symmetry(object):
|
|
353
360
|
logger.debug("end of check_delta: BAD DELTA %s, (expected %s)",
|
354
361
|
delta_angle, geom_alpha)
|
355
362
|
result['slices'] = 0
|
363
|
+
logger.debug("end of check_delta: very bad")
|
356
364
|
return result # very bad
|
357
365
|
|
358
366
|
deltas = self.create_deltas(delta_list, rtol=rtol, atol=atol)
|
@@ -927,13 +935,20 @@ class Symmetry(object):
|
|
927
935
|
logger.debug("Symmetry-Destroyer destroyed")
|
928
936
|
slices = None
|
929
937
|
|
938
|
+
if rslt.get('upper_quarter', False):
|
939
|
+
if size < max_size / 20:
|
940
|
+
slices = None
|
941
|
+
|
942
|
+
if slices == 1:
|
943
|
+
if rslt.get('upper_quarter', False):
|
944
|
+
slices = None
|
945
|
+
|
930
946
|
if slices == 1:
|
931
947
|
# symmetry killer
|
932
948
|
if areas < max(2, max_areas / 6):
|
933
949
|
if size < max_size * 0.05:
|
934
950
|
slices = None # ignore tiny areas
|
935
951
|
|
936
|
-
|
937
952
|
parts_possible = self.calc_parts(parts_possible, slices)
|
938
953
|
|
939
954
|
if unsure_sym:
|