femagtools 1.3.1__py3-none-any.whl → 1.3.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/airgap.py +11 -37
- femagtools/amela.py +2 -1
- femagtools/bch.py +19 -3
- femagtools/dxfsl/area.py +56 -15
- femagtools/dxfsl/converter.py +2 -0
- femagtools/dxfsl/geom.py +160 -41
- femagtools/dxfsl/machine.py +80 -3
- femagtools/ecloss.py +5 -3
- femagtools/femag.py +7 -1
- femagtools/isa7.py +35 -22
- femagtools/machine/effloss.py +4 -1
- femagtools/machine/utils.py +12 -8
- femagtools/model.py +11 -1
- femagtools/plot.py +33 -9
- femagtools/templates/afm_rotor.mako +102 -0
- femagtools/templates/afm_stator.mako +141 -0
- femagtools/templates/basic_modpar.mako +23 -2
- femagtools/templates/cogg_calc.mako +28 -5
- femagtools/templates/cu_losses.mako +1 -1
- femagtools/templates/fieldcalc.mako +39 -0
- femagtools/templates/gen_winding.mako +52 -47
- femagtools/templates/mesh-airgap.mako +43 -0
- femagtools/templates/stator3Linear.mako +5 -4
- femagtools/templates/therm-static.mako +12 -0
- femagtools/templates/torq_calc.mako +2 -4
- femagtools/utils.py +45 -0
- femagtools/windings.py +2 -1
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/METADATA +1 -1
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/RECORD +34 -30
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/WHEEL +1 -1
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/LICENSE +0 -0
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/airgap.py
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
"""
|
10
10
|
import numpy as np
|
11
11
|
import logging
|
12
|
+
from . import utils
|
12
13
|
|
13
14
|
logger = logging.getLogger(__name__)
|
14
15
|
|
@@ -22,49 +23,22 @@ def fft(pos, b, pmod=0):
|
|
22
23
|
b: (list of floats) flux density values
|
23
24
|
pmod: number of poles in model (ignored if 0)
|
24
25
|
"""
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
negative_periodic = pmod % 2
|
30
|
-
else:
|
31
|
-
negative_periodic = np.abs(b[0] - b[-1])/np.max(b) > 1
|
32
|
-
|
33
|
-
if negative_periodic:
|
34
|
-
bx = np.append(
|
35
|
-
np.concatenate(
|
36
|
-
[n*b[:-1]
|
37
|
-
for n in [m % 2 or -1
|
38
|
-
for m in range(1, ntiles+1)]]),
|
39
|
-
b[0])
|
40
|
-
else:
|
41
|
-
bx = np.append(
|
42
|
-
np.tile(b[:-1], ntiles),
|
43
|
-
b[0])
|
44
|
-
|
45
|
-
N = len(bx)
|
46
|
-
# compute DFT from induction
|
47
|
-
Y = np.fft.fft(bx)
|
48
|
-
|
49
|
-
# find the peak (amplitude of base harmonic)
|
50
|
-
i = np.argmax(np.abs(Y[:N//2]))
|
51
|
-
a = 2*np.abs(Y[i])/N
|
52
|
-
freq = np.fft.fftfreq(N, d=pos[1]-pos[0])
|
53
|
-
T0 = np.abs(1/freq[i])
|
26
|
+
r = utils.fft(pos, b, pmod)
|
27
|
+
Bamp = r['a']
|
28
|
+
alfa0 = r['alfa0']
|
29
|
+
T0 = r['T0']
|
54
30
|
npoles = 2*int(np.ceil(360/T0))
|
55
31
|
logger.info("flux density: %s poles B amp %f ",
|
56
|
-
npoles, a)
|
57
|
-
|
58
|
-
alfa0 = np.angle(Y[i])
|
59
|
-
return dict(Bamp=a, npoles=npoles,
|
32
|
+
npoles, r['a'])
|
33
|
+
return dict(Bamp=Bamp, npoles=npoles,
|
60
34
|
phi0=alfa0,
|
61
35
|
pos=pos.tolist(),
|
62
36
|
B=b.tolist(),
|
63
37
|
nue=np.arange(0, 9*npoles).tolist(),
|
64
|
-
B_nue=
|
65
|
-
B_fft=(
|
66
|
-
Bi=
|
67
|
-
phi=np.linspace(pos[0], 360+pos[0], len(
|
38
|
+
B_nue=r['nue'],
|
39
|
+
B_fft=(Bamp*np.cos(2*np.pi*pos/T0+alfa0)).tolist(),
|
40
|
+
Bi=r['yi'],
|
41
|
+
phi=np.linspace(pos[0], 360+pos[0], len(r['yi'])).tolist())
|
68
42
|
|
69
43
|
|
70
44
|
def read(filename, pmod=0):
|
femagtools/amela.py
CHANGED
femagtools/bch.py
CHANGED
@@ -170,6 +170,7 @@ class Reader:
|
|
170
170
|
self.dqPar = {}
|
171
171
|
self.ldq = {}
|
172
172
|
self.losses = []
|
173
|
+
self.magnet_loss_th = []
|
173
174
|
self.demag = []
|
174
175
|
self.weights = []
|
175
176
|
self.weight = {}
|
@@ -1497,11 +1498,12 @@ class Reader:
|
|
1497
1498
|
if l.find('Fe-Losses-Rotor') > -1:
|
1498
1499
|
rec = self.__findNums(content[i+3])
|
1499
1500
|
if len(rec) == 2:
|
1500
|
-
if content[i+1].find('Iron') > -1 and content[i+1].find('StJo') > 0
|
1501
|
+
if (content[i+1].find('Iron') > -1 and content[i+1].find('StJo') > 0 or
|
1502
|
+
content[i+1].split() == ['RoZa', 'RoJo']):
|
1501
1503
|
self.external_rotor = True
|
1502
1504
|
# TODO: there might be better places to check this
|
1503
|
-
losses['
|
1504
|
-
losses['
|
1505
|
+
losses['staza'] = floatnan(rec[0])
|
1506
|
+
losses['stajo'] = floatnan(rec[1])
|
1505
1507
|
losses['total'] += losses['staza']+losses['stajo']
|
1506
1508
|
else:
|
1507
1509
|
losses['rotfe'] = floatnan(rec[1])
|
@@ -1509,6 +1511,20 @@ class Reader:
|
|
1509
1511
|
i += 4
|
1510
1512
|
continue
|
1511
1513
|
|
1514
|
+
if l.find('Fe-Losses-Stator') > -1:
|
1515
|
+
rec = self.__findNums(content[i+3])
|
1516
|
+
if len(rec) == 2:
|
1517
|
+
if content[i+1].split() == ['StJo', 'StZa']:
|
1518
|
+
losses['stajo'] = floatnan(rec[0])
|
1519
|
+
losses['staza'] = floatnan(rec[1])
|
1520
|
+
losses['total'] += losses['staza']+losses['stajo']
|
1521
|
+
|
1522
|
+
if content[i+1].split() == ['rotf', '----']:
|
1523
|
+
losses['rotfe'] = sum([floatnan(x) for x in rec])
|
1524
|
+
losses['total'] += losses['rotfe']
|
1525
|
+
i += 4
|
1526
|
+
continue
|
1527
|
+
|
1512
1528
|
if l.find('Magnet-Losses') > -1:
|
1513
1529
|
rec = self.__findNums(content[i+1])
|
1514
1530
|
if len(rec) == 1:
|
femagtools/dxfsl/area.py
CHANGED
@@ -39,6 +39,8 @@ class Area(object):
|
|
39
39
|
self.min_air_angle = 0.0
|
40
40
|
self.max_air_angle = 0.0
|
41
41
|
self.close_to_ag = False
|
42
|
+
self.close_to_ag_startcorner = False
|
43
|
+
self.close_to_ag_endcorner = False
|
42
44
|
self.close_to_startangle = False
|
43
45
|
self.close_to_endangle = False
|
44
46
|
self.mag_rectangle = False
|
@@ -1056,6 +1058,12 @@ class Area(object):
|
|
1056
1058
|
return True
|
1057
1059
|
return False
|
1058
1060
|
|
1061
|
+
def is_touching_areas(self, areas):
|
1062
|
+
for a in areas:
|
1063
|
+
if self.is_touching(a):
|
1064
|
+
return True
|
1065
|
+
return False
|
1066
|
+
|
1059
1067
|
def mark_stator_subregions(self,
|
1060
1068
|
is_inner,
|
1061
1069
|
stator_size,
|
@@ -1155,18 +1163,37 @@ class Area(object):
|
|
1155
1163
|
logger.debug("***** air (part of a circle)\n")
|
1156
1164
|
return self.type
|
1157
1165
|
|
1166
|
+
def bad_winding_position():
|
1167
|
+
if is_inner:
|
1168
|
+
radius_third = airgap_radius - (airgap_radius - opposite_radius) * 0.33
|
1169
|
+
if self.max_dist < radius_third:
|
1170
|
+
return True
|
1171
|
+
else: # outer
|
1172
|
+
radius_third = airgap_radius + (opposite_radius - airgap_radius) * 0.33
|
1173
|
+
if self.min_dist > radius_third:
|
1174
|
+
return True
|
1175
|
+
return False
|
1176
|
+
|
1158
1177
|
if self.min_angle > 0.001:
|
1159
1178
|
if self.max_angle < alpha - 0.001:
|
1160
|
-
|
1161
|
-
|
1179
|
+
if bad_winding_position():
|
1180
|
+
self.type = 12 # windings or air
|
1181
|
+
logger.debug("***** windings or air #1\n")
|
1182
|
+
else:
|
1183
|
+
self.type = 2 # windings
|
1184
|
+
logger.debug("***** windings #1\n")
|
1162
1185
|
return self.type
|
1163
1186
|
if mirrored:
|
1164
|
-
|
1165
|
-
|
1187
|
+
if bad_winding_position():
|
1188
|
+
self.type = 12 # windings or air
|
1189
|
+
logger.debug("***** windings or air #2\n")
|
1190
|
+
else:
|
1191
|
+
self.type = 2 # windings
|
1192
|
+
logger.debug("***** windings #2\n")
|
1166
1193
|
return self.type
|
1167
1194
|
|
1168
1195
|
self.type = 0 # air
|
1169
|
-
logger.debug("***** air #
|
1196
|
+
logger.debug("***** air #3")
|
1170
1197
|
|
1171
1198
|
if self.close_to_startangle or self.close_to_endangle:
|
1172
1199
|
f = self.surface / stator_size
|
@@ -1179,7 +1206,7 @@ class Area(object):
|
|
1179
1206
|
logger.debug("***** air or iron close to border\n")
|
1180
1207
|
return self.type
|
1181
1208
|
|
1182
|
-
logger.debug("***** air #
|
1209
|
+
logger.debug("***** air #4\n")
|
1183
1210
|
return 0
|
1184
1211
|
|
1185
1212
|
def mark_rotor_subregions(self, is_inner, mirrored, alpha,
|
@@ -1331,6 +1358,15 @@ class Area(object):
|
|
1331
1358
|
logger.debug(">>> air remains")
|
1332
1359
|
return self.type
|
1333
1360
|
|
1361
|
+
def mark_airgap_corners(self, start_cp, end_cp):
|
1362
|
+
for n in self.list_of_nodes():
|
1363
|
+
if self.close_to_startangle:
|
1364
|
+
if points_are_close(n, start_cp):
|
1365
|
+
self.close_to_ag_startcorner = True
|
1366
|
+
if self.close_to_endangle:
|
1367
|
+
if points_are_close(n, end_cp):
|
1368
|
+
self.close_to_ag_endcorner = True
|
1369
|
+
|
1334
1370
|
def area_size(self):
|
1335
1371
|
nodes = [n for n in self.list_of_nodes()]
|
1336
1372
|
return area_size(nodes)
|
@@ -1467,14 +1503,19 @@ class Area(object):
|
|
1467
1503
|
|
1468
1504
|
def __str__(self):
|
1469
1505
|
return "Area {}\n".format(self.id) + \
|
1470
|
-
"distance
|
1506
|
+
"distance...............: from {} to {}\n".\
|
1471
1507
|
format(round(self.min_dist, 4), round(self.max_dist, 4)) + \
|
1472
|
-
"height
|
1473
|
-
"alpha
|
1474
|
-
"angle
|
1508
|
+
"height.................: {}\n".format(self.height) + \
|
1509
|
+
"alpha..................: {}\n".format(self.alpha) + \
|
1510
|
+
"angle..................: from {} to {}\n".\
|
1475
1511
|
format(round(self.min_angle, 6), round(self.max_angle, 6)) + \
|
1476
|
-
"delta
|
1477
|
-
"number
|
1478
|
-
"equal
|
1479
|
-
"symmetry
|
1480
|
-
"
|
1512
|
+
"delta..................: {}\n".format(self.delta) + \
|
1513
|
+
"number.................: {}\n".format(self.count) + \
|
1514
|
+
"equal areas............: {}\n".format(len(self.equal_areas)) + \
|
1515
|
+
"symmetry...............: {}\n".format(self.symmetry) + \
|
1516
|
+
"symmetry type..........: {}\n".format(self.sym_type) + \
|
1517
|
+
"close to airgap........: {}\n".format(self.close_to_ag) + \
|
1518
|
+
"close to startangle....: {}\n".format(self.close_to_startangle) + \
|
1519
|
+
"close to endangle......: {}\n".format(self.close_to_endangle) + \
|
1520
|
+
"close to ag startcorner: {}\n".format(self.close_to_ag_startcorner) + \
|
1521
|
+
"close to ag endcorner..: {}\n".format(self.close_to_ag_endcorner)
|
femagtools/dxfsl/converter.py
CHANGED
@@ -399,6 +399,7 @@ def convert(dxfile,
|
|
399
399
|
machine = machine.undo_mirror()
|
400
400
|
machine.geom.set_stator()
|
401
401
|
machine.geom.search_stator_subregions(part[1])
|
402
|
+
machine.geom.looking_for_corners()
|
402
403
|
machine.create_mirror_lines_outside_windings()
|
403
404
|
|
404
405
|
params = create_femag_parameters_stator(machine,
|
@@ -406,6 +407,7 @@ def convert(dxfile,
|
|
406
407
|
else:
|
407
408
|
machine.geom.set_rotor()
|
408
409
|
machine.geom.search_rotor_subregions(part[1])
|
410
|
+
machine.geom.looking_for_corners()
|
409
411
|
params = create_femag_parameters_rotor(machine,
|
410
412
|
part[1])
|
411
413
|
else:
|
femagtools/dxfsl/geom.py
CHANGED
@@ -276,6 +276,32 @@ def lw_polyline(entity, lf, xoff=0.0, yoff=0.0, rotation=0.0):
|
|
276
276
|
xoff=xoff, yoff=yoff,
|
277
277
|
rotation=rotation)
|
278
278
|
|
279
|
+
def ellipse(entity, lf, xoff=0.0, yoff=0.0, rotation=0.0):
|
280
|
+
w = np.linalg.norm(entity.major_axis) * 2
|
281
|
+
h = entity.ratio * w
|
282
|
+
theta = np.arctan2(entity.major_axis[1], entity.major_axis[0])
|
283
|
+
start_angle = entity.start_param
|
284
|
+
end_angle = entity.end_param
|
285
|
+
if end_angle < start_angle:
|
286
|
+
end_angle += 2*np.pi
|
287
|
+
alfa = np.linspace(start_angle, end_angle, 20)
|
288
|
+
x = 0.5 * w * np.cos(alfa)
|
289
|
+
y = 0.5 * h * np.sin(alfa)
|
290
|
+
R = np.array([
|
291
|
+
[np.cos(theta), -np.sin(theta)],
|
292
|
+
[np.sin(theta), np.cos(theta)]
|
293
|
+
])
|
294
|
+
x, y = np.dot(R, [x, y])
|
295
|
+
x += entity.center[0]
|
296
|
+
y += entity.center[1]
|
297
|
+
points = np.array((x,y)).T
|
298
|
+
p1 = points[0]
|
299
|
+
for p2 in points[1:]:
|
300
|
+
yield Line(Element(start=p1, end=p2), lf,
|
301
|
+
xoff=xoff, yoff=yoff,
|
302
|
+
rotation=rotation)
|
303
|
+
p1 = p2
|
304
|
+
|
279
305
|
|
280
306
|
def spline(entity, lf, min_dist=0.001, xoff=0.0, yoff=0.0, rotation=0.0):
|
281
307
|
if False:
|
@@ -493,22 +519,26 @@ def dxfshapes(dxffile, mindist=0.01, layers=[]):
|
|
493
519
|
for l in insert_block(dwg, e, lf, rf, block, min_dist=mindist):
|
494
520
|
yield l
|
495
521
|
elif e.dxftype == 'ELLIPSE':
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
522
|
+
for l in ellipse(e, lf):
|
523
|
+
yield l
|
524
|
+
#w = np.linalg.norm(e.major_axis) * 2
|
525
|
+
#h = e.ratio * w
|
526
|
+
#rtheta = np.arctan2(e.major_axis[1], e.major_axis[0])
|
527
|
+
#angle = rtheta*180/np.pi
|
528
|
+
#start_angle = e.start_param*180/np.pi + angle
|
529
|
+
#end_angle = e.end_param*180/np.pi + angle
|
530
|
+
#if end_angle < start_angle:
|
531
|
+
# end_angle += 360
|
532
|
+
#arc = Arc(Element(center=e.center,
|
533
|
+
# radius=w/2,
|
534
|
+
# start_angle=start_angle,
|
535
|
+
# end_angle=end_angle,
|
536
|
+
# width=w,
|
537
|
+
# height=h,
|
538
|
+
# rtheta=rtheta,
|
539
|
+
# start_param=e.start_param,
|
540
|
+
# end_param=e.end_param))
|
541
|
+
#yield arc
|
512
542
|
|
513
543
|
elif e.dxftype == 'POINT':
|
514
544
|
logger.debug("Id %d4: type %s ignored", id, e.dxftype)
|
@@ -994,12 +1024,28 @@ class Geometry(object):
|
|
994
1024
|
def add_line(self, n1, n2, color=None):
|
995
1025
|
line = Line(Element(start=n1, end=n2), color=color)
|
996
1026
|
add_or_join(self,
|
997
|
-
|
998
|
-
|
1027
|
+
n1,
|
1028
|
+
n2,
|
999
1029
|
line,
|
1000
1030
|
self.rtol,
|
1001
1031
|
self.atol)
|
1002
1032
|
|
1033
|
+
def add_arc(self, n1, n2, center, radius, color=None):
|
1034
|
+
angle_n1 = alpha_line(center, n1)
|
1035
|
+
angle_n2 = alpha_line(center, n2)
|
1036
|
+
arc = Arc(Element(center=center,
|
1037
|
+
radius=radius,
|
1038
|
+
start_angle=angle_n1*180/np.pi,
|
1039
|
+
end_angle=angle_n2*180/np.pi),
|
1040
|
+
color=color)
|
1041
|
+
add_or_join(self,
|
1042
|
+
n1,
|
1043
|
+
n2,
|
1044
|
+
arc,
|
1045
|
+
self.rtol,
|
1046
|
+
self.atol)
|
1047
|
+
|
1048
|
+
|
1003
1049
|
def elements(self, type):
|
1004
1050
|
"""return lists of objects"""
|
1005
1051
|
return [e[2]['object'] for e in self.g.edges(data=True)
|
@@ -2631,7 +2677,7 @@ class Geometry(object):
|
|
2631
2677
|
dist_max = max(dist_max, g[1])
|
2632
2678
|
return airgaps
|
2633
2679
|
|
2634
|
-
def detect_airgaps(self, center, startangle, endangle, atol):
|
2680
|
+
def detect_airgaps(self, center, startangle, endangle, atol=0.1, with_end=False):
|
2635
2681
|
""" Die Funktion sucht Luftspalt-Kandidaten und liefert eine Liste
|
2636
2682
|
von Möglichkeiten mit jeweils einem minimalen und einem maximalen
|
2637
2683
|
Radius als Begrenzung des Luftspalts.
|
@@ -2651,6 +2697,8 @@ class Geometry(object):
|
|
2651
2697
|
min_radius = self.min_radius + 1.0
|
2652
2698
|
cur_radius = gaplist[0][1]
|
2653
2699
|
max_radius = self.max_radius - 1.0
|
2700
|
+
if with_end:
|
2701
|
+
max_radius = self.max_radius + 1.0
|
2654
2702
|
|
2655
2703
|
for g in gaplist:
|
2656
2704
|
if greater(g[0], cur_radius) and \
|
@@ -3024,13 +3072,31 @@ class Geometry(object):
|
|
3024
3072
|
|
3025
3073
|
def search_subregions(self):
|
3026
3074
|
if self.is_stator():
|
3027
|
-
|
3075
|
+
self.search_stator_subregions()
|
3076
|
+
elif self.is_rotor():
|
3077
|
+
self.search_rotor_subregions()
|
3078
|
+
else:
|
3079
|
+
logger.warning("no stator or rotor assigned")
|
3080
|
+
self.search_unknown_subregions()
|
3081
|
+
self.looking_for_corners()
|
3028
3082
|
|
3029
|
-
|
3030
|
-
|
3083
|
+
def collect_windings(self):
|
3084
|
+
found = True
|
3085
|
+
while found:
|
3086
|
+
windings = [a for a in self.list_of_areas()
|
3087
|
+
if a.type == 2]
|
3088
|
+
bad_windings = [a for a in self.list_of_areas()
|
3089
|
+
if a.type == 12]
|
3090
|
+
if not bad_windings:
|
3091
|
+
return windings
|
3092
|
+
|
3093
|
+
found = False
|
3094
|
+
for a in bad_windings:
|
3095
|
+
if a.is_touching_areas(windings):
|
3096
|
+
a.type = 2
|
3097
|
+
found = True
|
3031
3098
|
|
3032
|
-
|
3033
|
-
return self.search_unknown_subregions()
|
3099
|
+
return [a for a in self.list_of_areas() if a.type == 2]
|
3034
3100
|
|
3035
3101
|
def search_stator_subregions(self, place=''):
|
3036
3102
|
logger.debug("Begin of search_stator_subregions")
|
@@ -3053,8 +3119,8 @@ class Geometry(object):
|
|
3053
3119
|
self.min_radius,
|
3054
3120
|
self.max_radius)
|
3055
3121
|
|
3056
|
-
windings =
|
3057
|
-
|
3122
|
+
windings = self.collect_windings()
|
3123
|
+
[a.set_type(0) for a in self.list_of_areas() if a.type == 12]
|
3058
3124
|
windings_found = len(windings)
|
3059
3125
|
logger.info("%d windings found", windings_found)
|
3060
3126
|
|
@@ -3063,7 +3129,7 @@ class Geometry(object):
|
|
3063
3129
|
windings_surface.sort(reverse=True)
|
3064
3130
|
max_size = windings_surface[0][0]
|
3065
3131
|
for sz, w in windings_surface:
|
3066
|
-
logger.
|
3132
|
+
logger.debug("winding size = %s", sz)
|
3067
3133
|
if sz / max_size < 0.95:
|
3068
3134
|
w.set_type(0)
|
3069
3135
|
if sz / max_size < 0.2:
|
@@ -3328,7 +3394,21 @@ class Geometry(object):
|
|
3328
3394
|
if a.surface < max_surface * 0.20: # too small
|
3329
3395
|
a.set_type(0) # air
|
3330
3396
|
|
3331
|
-
logger.debug("
|
3397
|
+
logger.debug("end of search_unknown_subregions")
|
3398
|
+
|
3399
|
+
def looking_for_corners(self):
|
3400
|
+
if self.is_inner:
|
3401
|
+
logger.debug("looking_for_corners: inner")
|
3402
|
+
start_cp = self.start_corners[-1]
|
3403
|
+
end_cp = self.end_corners[-1]
|
3404
|
+
else:
|
3405
|
+
logger.debug("looking_for_corners: outer")
|
3406
|
+
start_cp = self.start_corners[0]
|
3407
|
+
end_cp = self.end_corners[0]
|
3408
|
+
logger.debug("looking_for_corners: start=%s, end=%s",
|
3409
|
+
start_cp, end_cp)
|
3410
|
+
for area in self.list_of_areas():
|
3411
|
+
area.mark_airgap_corners(start_cp, end_cp)
|
3332
3412
|
return
|
3333
3413
|
|
3334
3414
|
def num_areas_of_type(self, type):
|
@@ -3581,19 +3661,16 @@ class Geometry(object):
|
|
3581
3661
|
c += self.remove_appendix(n2, nbrs[0], incr_text + '.')
|
3582
3662
|
return c
|
3583
3663
|
|
3584
|
-
def split_and_get_intersect_points(self,
|
3664
|
+
def split_and_get_intersect_points(self, el, aktion=True):
|
3585
3665
|
logger.debug("begin of split_and_get_intersect_points")
|
3586
3666
|
rtol = 1e-03
|
3587
3667
|
atol = 1e-03
|
3588
|
-
line = Line(
|
3589
|
-
Element(start=center,
|
3590
|
-
end=point(center, outer_radius+1, angle)))
|
3591
3668
|
points = []
|
3592
3669
|
for e in self.elements(Shape):
|
3593
|
-
pts = e.
|
3594
|
-
|
3595
|
-
|
3596
|
-
|
3670
|
+
pts = e.intersect_shape(el,
|
3671
|
+
rtol=rtol,
|
3672
|
+
atol=atol,
|
3673
|
+
include_end=True)
|
3597
3674
|
if pts:
|
3598
3675
|
pts_inside = []
|
3599
3676
|
pts_real = []
|
@@ -3608,7 +3685,7 @@ class Geometry(object):
|
|
3608
3685
|
pts_real.append(p)
|
3609
3686
|
pts_inside.append(p)
|
3610
3687
|
|
3611
|
-
if pts_inside:
|
3688
|
+
if pts_inside and aktion:
|
3612
3689
|
self.remove_edge(e)
|
3613
3690
|
elements = e.split(pts_inside, rtol, atol)
|
3614
3691
|
for e in elements:
|
@@ -3631,6 +3708,31 @@ class Geometry(object):
|
|
3631
3708
|
return True
|
3632
3709
|
return False
|
3633
3710
|
|
3711
|
+
def inside_area_list(self, p):
|
3712
|
+
for area in self.list_of_areas():
|
3713
|
+
if area.is_point_inside(p):
|
3714
|
+
yield area
|
3715
|
+
|
3716
|
+
def critical_touch_point(self, points):
|
3717
|
+
logger.debug("looking for critical touch-point")
|
3718
|
+
winding_touched = False
|
3719
|
+
for p in points[1:]:
|
3720
|
+
d = distance(self.center, p)
|
3721
|
+
logger.debug("-- p = %s, dist = %s", p, d)
|
3722
|
+
for a in self.inside_area_list(p):
|
3723
|
+
logger.debug("-- Area type = %s", a.type)
|
3724
|
+
logger.debug(" min=%s, max= %s", a.min_dist, a.max_dist)
|
3725
|
+
logger.debug(" close to start = %s", a.close_to_startangle)
|
3726
|
+
logger.debug(" close to end = %s", a.close_to_endangle)
|
3727
|
+
if a.is_winding():
|
3728
|
+
winding_touched = True
|
3729
|
+
else:
|
3730
|
+
if winding_touched and greater(a.max_dist, d, atol=0.001):
|
3731
|
+
if not (a.close_to_startangle and a.close_to_endangle):
|
3732
|
+
logger.debug("-- return %s", p)
|
3733
|
+
return p
|
3734
|
+
return None
|
3735
|
+
|
3634
3736
|
def create_lines_outside_windings(self, points):
|
3635
3737
|
if not points:
|
3636
3738
|
return False
|
@@ -3661,16 +3763,23 @@ class Geometry(object):
|
|
3661
3763
|
return False
|
3662
3764
|
|
3663
3765
|
def get_inner_airgap_line(self):
|
3766
|
+
logger.debug("begin of get_inner_airgap_line")
|
3767
|
+
|
3664
3768
|
if not self.is_inner:
|
3769
|
+
logger.debug("end of get_inner_airgap_line: not inner")
|
3665
3770
|
return []
|
3666
|
-
|
3771
|
+
for a in self.area_list:
|
3772
|
+
logger.debug("%s", a)
|
3773
|
+
area = [a for a in self.area_list if a.close_to_ag_endcorner]
|
3667
3774
|
if len(area) != 1:
|
3775
|
+
logger.debug("end of get_inner_airgap_line: %s areas found", len(area))
|
3668
3776
|
return []
|
3669
3777
|
|
3670
3778
|
end_corner = self.end_corners[-1]
|
3671
3779
|
logger.debug("END CORNER %s", end_corner)
|
3672
3780
|
nodes = [n for n in area[0].list_of_nodes()]
|
3673
3781
|
if not nodes:
|
3782
|
+
logger.debug("end of get_inner_airgap_line: no nodes found")
|
3674
3783
|
return []
|
3675
3784
|
n1 = nodes[0]
|
3676
3785
|
if points_are_close(end_corner, n1):
|
@@ -3683,6 +3792,7 @@ class Geometry(object):
|
|
3683
3792
|
n2 = n1
|
3684
3793
|
|
3685
3794
|
if not points_are_close(end_corner, n1):
|
3795
|
+
logger.debug("end of get_inner_airgap_line: not close to endcorner")
|
3686
3796
|
return []
|
3687
3797
|
|
3688
3798
|
start_corner = self.start_corners[-1]
|
@@ -3697,6 +3807,7 @@ class Geometry(object):
|
|
3697
3807
|
n2 = info['n2']
|
3698
3808
|
nodes.append(n2)
|
3699
3809
|
|
3810
|
+
logger.debug("end of get_inner_airgap_line #%s", len(nodes))
|
3700
3811
|
return nodes
|
3701
3812
|
|
3702
3813
|
def create_corner_areas(self):
|
@@ -3743,7 +3854,11 @@ class Geometry(object):
|
|
3743
3854
|
if not self.search_intersection(i, self.max_radius,
|
3744
3855
|
n, start_cp,
|
3745
3856
|
airgap_nodes):
|
3746
|
-
self.
|
3857
|
+
d = distance(self.center, n)
|
3858
|
+
if np.isclose(d, self.max_radius):
|
3859
|
+
self.add_arc(start_cp, n, self.center, self.max_radius, color='red')
|
3860
|
+
else:
|
3861
|
+
self.add_line(start_cp, n, color='red')
|
3747
3862
|
self.add_edge(cp, start_cp, start_line)
|
3748
3863
|
self.create_and_append_area(start_cp, n)
|
3749
3864
|
self.start_corners = self.get_corner_nodes(self.center,
|
@@ -3762,7 +3877,11 @@ class Geometry(object):
|
|
3762
3877
|
if not self.search_intersection(i, self.max_radius,
|
3763
3878
|
n, end_cp,
|
3764
3879
|
airgap_nodes):
|
3765
|
-
self.
|
3880
|
+
d = distance(self.center, n)
|
3881
|
+
if np.isclose(d, self.max_radius):
|
3882
|
+
self.add_arc(n, end_cp, self.center, self.max_radius, color='red')
|
3883
|
+
else:
|
3884
|
+
self.add_line(end_cp, n, color='red')
|
3766
3885
|
self.add_edge(cp, end_cp, end_line)
|
3767
3886
|
self.create_and_append_area(n, end_cp)
|
3768
3887
|
self.end_corners = self.get_corner_nodes(self.center,
|
@@ -3788,7 +3907,7 @@ class Geometry(object):
|
|
3788
3907
|
logger.debug("end of search_intersection: bad")
|
3789
3908
|
return True # fatal
|
3790
3909
|
dist_p = distance(self.center, pts[0])
|
3791
|
-
logger.
|
3910
|
+
logger.debug("-- check point %s[%s] -- %s[%s]", n, dist_n, pts[0], dist_p)
|
3792
3911
|
if not less(dist_n, dist_p):
|
3793
3912
|
logger.debug("end of search_intersection: found")
|
3794
3913
|
return True # intersection
|