femagtools 1.8.18__py3-none-any.whl → 1.8.20__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/bch.py +23 -6
- femagtools/dxfsl/area.py +12 -1
- femagtools/dxfsl/areabuilder.py +28 -12
- femagtools/dxfsl/converter.py +7 -2
- femagtools/dxfsl/fslrenderer.py +47 -14
- femagtools/dxfsl/geom.py +110 -39
- femagtools/dxfsl/machine.py +107 -2
- femagtools/dxfsl/shape.py +7 -0
- femagtools/femag.py +3 -3
- femagtools/isa7.py +25 -22
- femagtools/machine/__init__.py +2 -2
- femagtools/machine/effloss.py +8 -0
- femagtools/machine/pm.py +18 -7
- femagtools/machine/sm.py +17 -6
- femagtools/mcv.py +4 -1
- femagtools/model.py +7 -1
- femagtools/shortcircuit.py +8 -7
- femagtools/templates/psi-torq-rem.mako +4 -4
- femagtools/templates/statorKS1.mako +43 -0
- {femagtools-1.8.18.dist-info → femagtools-1.8.20.dist-info}/METADATA +1 -1
- {femagtools-1.8.18.dist-info → femagtools-1.8.20.dist-info}/RECORD +26 -25
- {femagtools-1.8.18.dist-info → femagtools-1.8.20.dist-info}/WHEEL +0 -0
- {femagtools-1.8.18.dist-info → femagtools-1.8.20.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.18.dist-info → femagtools-1.8.20.dist-info}/licenses/LICENSE +0 -0
- {femagtools-1.8.18.dist-info → femagtools-1.8.20.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/bch.py
CHANGED
@@ -271,7 +271,7 @@ class Reader:
|
|
271
271
|
return self.flux[0]['displ'][1]-self.flux[0]['displ'][0]
|
272
272
|
return None
|
273
273
|
|
274
|
-
def read(self, content):
|
274
|
+
def read(self, content, **kwargs):
|
275
275
|
"""read bch file
|
276
276
|
|
277
277
|
Args:
|
@@ -297,7 +297,10 @@ class Reader:
|
|
297
297
|
if k == title2[:len(k)]:
|
298
298
|
title = title2[:len(k)]
|
299
299
|
if title in self.dispatch:
|
300
|
-
|
300
|
+
if title == 'Airgap Induction Br':
|
301
|
+
self.dispatch[title](self, s, kwargs.get('ignore_airgap_induction_with_c_step_section', True))
|
302
|
+
else:
|
303
|
+
self.dispatch[title](self, s)
|
301
304
|
|
302
305
|
if len(self.weights) > 0:
|
303
306
|
w = list(zip(*self.weights))
|
@@ -887,7 +890,7 @@ class Reader:
|
|
887
890
|
self.flux_fft[self.wdg] = []
|
888
891
|
self.flux_fft[self.wdg].append(flux_fft)
|
889
892
|
|
890
|
-
def __read_airgapInduction(self, content):
|
893
|
+
def __read_airgapInduction(self, content, ignore_c_step_section=True):
|
891
894
|
"read and append airgapInduction section"
|
892
895
|
import scipy.integrate as si
|
893
896
|
import math
|
@@ -918,7 +921,9 @@ class Reader:
|
|
918
921
|
i1beta = True
|
919
922
|
continue
|
920
923
|
if line.startswith("C_STEP"):
|
921
|
-
|
924
|
+
if ignore_c_step_section:
|
925
|
+
return # ignore this section
|
926
|
+
continue
|
922
927
|
try:
|
923
928
|
rec = self.__findNums(line)
|
924
929
|
if len(rec) == 10:
|
@@ -966,6 +971,10 @@ class Reader:
|
|
966
971
|
self.airgapInduction['iq'] = iq
|
967
972
|
self.airgapInduction['id'] = id
|
968
973
|
nrows = len(self.airgapInduction['id'])
|
974
|
+
if not ignore_c_step_section:
|
975
|
+
# min 1 required (section with C_STEP)
|
976
|
+
nrows = max(1, nrows)
|
977
|
+
ncols = max(1, ncols)
|
969
978
|
|
970
979
|
try:
|
971
980
|
self.airgapInduction['an'] = [np.reshape(an[j][:nrows*ncols],
|
@@ -999,6 +1008,14 @@ class Reader:
|
|
999
1008
|
[1:])
|
1000
1009
|
self.airgapInduction['Bm'] = zip(*zip(*self.airgapInduction['Bm'])
|
1001
1010
|
[1:])
|
1011
|
+
elif not ignore_c_step_section:
|
1012
|
+
# section with C_STEP and a single data linex
|
1013
|
+
self.airgapInduction['an'] = [self.airgapInduction['an'][i][0:]
|
1014
|
+
for i in range(4)]
|
1015
|
+
self.airgapInduction['bn'] = [self.airgapInduction['bn'][i][0:]
|
1016
|
+
for i in range(4)]
|
1017
|
+
self.airgapInduction['Ba'] = self.airgapInduction['Ba'][0:]
|
1018
|
+
self.airgapInduction['Bm'] = self.airgapInduction['Bm'][0:]
|
1002
1019
|
except ValueError:
|
1003
1020
|
print(self.airgapInduction['i1'])
|
1004
1021
|
|
@@ -1858,12 +1875,12 @@ class Reader:
|
|
1858
1875
|
return self.__str__()
|
1859
1876
|
|
1860
1877
|
|
1861
|
-
def read(filename):
|
1878
|
+
def read(filename, **kwargs):
|
1862
1879
|
"""Read BCH/BATCH results from file *filename*."""
|
1863
1880
|
import io
|
1864
1881
|
bchresults = Reader()
|
1865
1882
|
with io.open(filename, encoding='latin1', errors='ignore') as f:
|
1866
|
-
bchresults.read(f.readlines())
|
1883
|
+
bchresults.read(f.readlines(), **kwargs)
|
1867
1884
|
return bchresults
|
1868
1885
|
|
1869
1886
|
|
femagtools/dxfsl/area.py
CHANGED
@@ -105,6 +105,12 @@ class Area(object):
|
|
105
105
|
def elements(self):
|
106
106
|
return self.area
|
107
107
|
|
108
|
+
def is_element_in_area(self, el):
|
109
|
+
for e in self.elements():
|
110
|
+
if el.has_same_nodes(e):
|
111
|
+
return True
|
112
|
+
return False
|
113
|
+
|
108
114
|
def copy_of_elements(self):
|
109
115
|
return [e.clone() for e in self.elements() if e]
|
110
116
|
|
@@ -1818,7 +1824,7 @@ class Area(object):
|
|
1818
1824
|
logger.debug(">>> air is a circle")
|
1819
1825
|
return self.type
|
1820
1826
|
|
1821
|
-
self.set_close_to_start_end_angles(
|
1827
|
+
self.set_close_to_start_end_angles(0.0, alpha)
|
1822
1828
|
|
1823
1829
|
if self.is_magnet_rectangle():
|
1824
1830
|
self.type = TYPE_MAGNET_RECT # magnet embedded
|
@@ -1863,6 +1869,11 @@ class Area(object):
|
|
1863
1869
|
nodes = [n for n in self.virtual_nodes(parts=4)]
|
1864
1870
|
return area_size(nodes)
|
1865
1871
|
|
1872
|
+
def get_area_size(self):
|
1873
|
+
if self.surface == 0.0:
|
1874
|
+
self.surface = self.area_size()
|
1875
|
+
return self.surface
|
1876
|
+
|
1866
1877
|
def set_surface(self, mirrored):
|
1867
1878
|
self.surface = self.area_size()
|
1868
1879
|
if self.close_to_endangle and mirrored:
|
femagtools/dxfsl/areabuilder.py
CHANGED
@@ -16,7 +16,7 @@ from femagtools.dxfsl.area import Area, TYPE_AIR
|
|
16
16
|
from femagtools.dxfsl.functions import points_are_close, nodes_are_equal, distance
|
17
17
|
from femagtools.dxfsl.functions import normalise_angle, positive_angle, point
|
18
18
|
from femagtools.dxfsl.functions import alpha_line, alpha_points, alpha_angle
|
19
|
-
from femagtools.dxfsl.functions import less, is_same_angle
|
19
|
+
from femagtools.dxfsl.functions import less, less_equal, greater, is_same_angle
|
20
20
|
from femagtools.dxfsl.functions import Timer
|
21
21
|
from femagtools.dxfsl.journal import getJournal
|
22
22
|
import io
|
@@ -135,7 +135,7 @@ class EdgeInfo(object):
|
|
135
135
|
self.angle = positive_angle(alpha_angle(start_angle, self.n1_angle_ingoing()))
|
136
136
|
logger.debug("set_direction_angle: angle is %s", self.angle)
|
137
137
|
|
138
|
-
if is_same_angle(0.0, self.angle, atol=0.
|
138
|
+
if is_same_angle(0.0, self.angle, atol=0.015): # 1/2 degree
|
139
139
|
# reverse direction
|
140
140
|
logger.debug("set_direction_angle: reverse direction( nearly 180 degrees)")
|
141
141
|
|
@@ -218,7 +218,7 @@ class EdgeInfo(object):
|
|
218
218
|
myself_angle = self.angle
|
219
219
|
other_angle = nbr_edge.angle
|
220
220
|
|
221
|
-
if is_same_angle(0.0, myself_angle):
|
221
|
+
if is_same_angle(0.0, myself_angle, atol=0.015):
|
222
222
|
# 360 or 0 degrees => turn 180 degrees
|
223
223
|
logger.debug("-- ATTENTION: myself %s turns nearly 180 degrees", self.classname())
|
224
224
|
logger.debug(" the angle is %s", myself_angle)
|
@@ -261,7 +261,7 @@ class EdgeInfo(object):
|
|
261
261
|
logger.debug("#4: end of myself_direction_lefthand: ==> %s", left)
|
262
262
|
return left
|
263
263
|
|
264
|
-
if is_same_angle(0.0, other_angle, atol=0.
|
264
|
+
if is_same_angle(0.0, other_angle, atol=0.015): # 1/2 degree
|
265
265
|
# 360 or 0 degrees => turn 180 degrees
|
266
266
|
logger.debug("-- ATTENTION: other %s turns nearly 180 degrees", nbr_edge.classname())
|
267
267
|
logger.debug(" the angle is %s", other_angle)
|
@@ -288,7 +288,7 @@ class EdgeInfo(object):
|
|
288
288
|
|
289
289
|
logger.debug("-- angles: myself = %s, other = %s",
|
290
290
|
myself_angle, other_angle)
|
291
|
-
if not is_same_angle(myself_angle, other_angle, atol=0.
|
291
|
+
if not is_same_angle(myself_angle, other_angle, atol=0.015): # 1/2 degree
|
292
292
|
logger.debug("-- angles are different")
|
293
293
|
left = myself_angle > other_angle
|
294
294
|
log_lefthand(left, self, nbr_edge)
|
@@ -778,7 +778,7 @@ class AreaBuilder(object):
|
|
778
778
|
assert(self.geom.area_list)
|
779
779
|
return self.get_lower_border_line()
|
780
780
|
|
781
|
-
def close_outer_winding_areas(self):
|
781
|
+
def close_outer_winding_areas(self, color='red'):
|
782
782
|
logger.debug("begin close_outer_winding_areas")
|
783
783
|
|
784
784
|
airgap_line, airgap_el = self.get_outer_airgap_line()
|
@@ -787,6 +787,15 @@ class AreaBuilder(object):
|
|
787
787
|
if len(airgap_line) < 5:
|
788
788
|
return False
|
789
789
|
|
790
|
+
distlist = [distance(self.geom.center, n) for n in airgap_line]
|
791
|
+
min_dist = min(distlist)
|
792
|
+
max_dist = max(distlist)
|
793
|
+
geom_height = self.geom.max_radius - self.geom.min_radius
|
794
|
+
line_height = max_dist - min_dist
|
795
|
+
if line_height < geom_height * 0.2:
|
796
|
+
return 0
|
797
|
+
|
798
|
+
logger.debug("NODES: %s TO %s", airgap_line[0], airgap_line[-1])
|
790
799
|
n1 = None
|
791
800
|
dist_n1 = 0.0
|
792
801
|
|
@@ -795,22 +804,29 @@ class AreaBuilder(object):
|
|
795
804
|
dist_prev = distance(self.geom.center, n_prev)
|
796
805
|
alpha_prev = alpha_line(self.geom.center, n_prev)
|
797
806
|
alpha_start = alpha_prev
|
798
|
-
|
799
807
|
lines_created = 0
|
808
|
+
dist_ag = self.geom.min_radius
|
809
|
+
logger.debug("MIN RADIUS DIST: %s",dist_ag)
|
800
810
|
for n in airgap_line[1:]:
|
801
811
|
dist = distance(self.geom.center, n)
|
802
812
|
alpha = alpha_line(self.geom.center, n)
|
813
|
+
logger.debug("Node %s, dist=%s, alpha=%s", n, dist, alpha)
|
803
814
|
if not n1:
|
804
|
-
|
805
|
-
|
806
|
-
|
815
|
+
logger.debug("Previous, dist=%s, alpha=%s", dist_prev, alpha_prev)
|
816
|
+
if greater(dist_prev, dist_ag, rtol=1e-3, atol=1e-3):
|
817
|
+
if greater(dist, dist_prev, rtol=1e-3, atol=1e-3) and \
|
818
|
+
less(alpha, alpha_prev, rtol=1e-4, atol=1e-5):
|
819
|
+
n1 = n_prev
|
820
|
+
dist_n1 = dist_prev
|
821
|
+
logger.debug("NODE1: %s (%s)", n1, dist_n1)
|
807
822
|
else:
|
808
|
-
if
|
823
|
+
if less_equal(dist, dist_n1, rtol=1e-3, atol=1e-2):
|
824
|
+
logger.debug("NODE2: %s (%s)", n, dist)
|
809
825
|
line = Line(Element(start=n1, end=n))
|
810
826
|
if e_prev.intersect_line(line):
|
811
827
|
logger.debug("___LINE NOT POSSIBLE___")
|
812
828
|
else:
|
813
|
-
self.geom.add_line(n1, n, color=
|
829
|
+
self.geom.add_line(n1, n, color=color)
|
814
830
|
lines_created += 1
|
815
831
|
n1 = None
|
816
832
|
dist_n1 = 0.0
|
femagtools/dxfsl/converter.py
CHANGED
@@ -229,7 +229,7 @@ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
|
|
229
229
|
else:
|
230
230
|
rebuild = machine_temp.create_mirror_lines_outside_magnets()
|
231
231
|
if rebuild:
|
232
|
-
machine_temp.
|
232
|
+
machine_temp.rebuild_subregions(EESM, single=single)
|
233
233
|
|
234
234
|
if machine_temp.create_auxiliary_lines():
|
235
235
|
logger.debug("Auxiliary Lines created: rebuild subregions")
|
@@ -286,6 +286,8 @@ def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False)
|
|
286
286
|
machine_temp.create_mirror_lines_outside_windings()
|
287
287
|
else:
|
288
288
|
machine_temp = machine
|
289
|
+
if machine_temp.has_windings_in_the_middle():
|
290
|
+
machine_temp.create_mirror_lines_outside_windings()
|
289
291
|
|
290
292
|
if machine_temp.geom.reduce_element_nodes(mindist):
|
291
293
|
machine_temp.rebuild_subregions(EESM, single=single)
|
@@ -309,6 +311,9 @@ def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False)
|
|
309
311
|
plt, machine_temp.geom,
|
310
312
|
title="Stator Winding Slice after Rebuild")
|
311
313
|
|
314
|
+
if machine_temp.remove_tiny_air_areas():
|
315
|
+
machine_temp.rebuild_subregions(EESM, single=single)
|
316
|
+
|
312
317
|
if machine_temp.create_auxiliary_lines():
|
313
318
|
machine_temp.rebuild_subregions(EESM, single=single)
|
314
319
|
plot_geom(False, # for developer
|
@@ -1037,7 +1042,7 @@ def create_femag_parameters(m_inner, m_outer, nodedist=1):
|
|
1037
1042
|
alfa_pole = geom_poles.get_alfa()
|
1038
1043
|
|
1039
1044
|
params['tot_num_slot'] = num_slots
|
1040
|
-
params['slot_area'] = slot_area
|
1045
|
+
params['slot_area'] = float(slot_area)
|
1041
1046
|
params['num_sl_gen'] = num_sl_gen
|
1042
1047
|
params['num_poles'] = num_poles
|
1043
1048
|
params['nodedist'] = nodedist
|
femagtools/dxfsl/fslrenderer.py
CHANGED
@@ -246,6 +246,37 @@ class FslRenderer(object):
|
|
246
246
|
'outer_da_end = {}'.format(
|
247
247
|
geom.dist_end_min_corner())
|
248
248
|
]
|
249
|
+
if inner:
|
250
|
+
r = np.linalg.norm(geom.start_corners[0])
|
251
|
+
if not np.isclose(geom.min_radius, r, rtol=1e-3):
|
252
|
+
slice = 1 if machine.is_mirrored() else 2
|
253
|
+
self.content += [
|
254
|
+
'-- create air layer inside',
|
255
|
+
'x0, y0 = {}, {}'.format(
|
256
|
+
geom.start_min_corner(0),
|
257
|
+
geom.start_min_corner(1)),
|
258
|
+
'hair = 1.0',
|
259
|
+
'parts = {}'.format(machine.get_num_parts()),
|
260
|
+
'rmin = {}'.format(geom.min_radius),
|
261
|
+
'r1 = rmin - hair',
|
262
|
+
'r, phi = c2pr(x0, y0)',
|
263
|
+
'x1, y1 = pr2c(r1, phi)',
|
264
|
+
'x2, y2 = pr2c(r1, {}*math.pi/parts)'.format(slice),
|
265
|
+
'x3, y3 = pr2c(r, {}*math.pi/parts)'.format(slice),
|
266
|
+
'nc_line(x0, y0, x1, y1, 0)',
|
267
|
+
'nc_circle_m(x1, y1, x2, y2, 0.0, 0.0, 0)',
|
268
|
+
'nc_line(x2, y2, x3, y3, 0)',
|
269
|
+
'x0, y0 = pr2c(rmin - hair/2, math.pi/parts/2)',
|
270
|
+
'create_mesh_se(x0, y0)',
|
271
|
+
'\n']
|
272
|
+
else:
|
273
|
+
self.content += [
|
274
|
+
'parts = {}'.format(machine.get_num_parts()),
|
275
|
+
'x0, y0 = {}, {}'.format(
|
276
|
+
geom.start_min_corner(0),
|
277
|
+
geom.start_min_corner(1)),
|
278
|
+
'r1, phi = c2pr(x0, y0)']
|
279
|
+
|
249
280
|
if self.mtype == 'PMSM':
|
250
281
|
self.content += [
|
251
282
|
'xmag = {}',
|
@@ -256,6 +287,9 @@ class FslRenderer(object):
|
|
256
287
|
'if mcvkey_yoke == nil then',
|
257
288
|
' mcvkey_yoke = "dummy"',
|
258
289
|
' ur = 1000.0',
|
290
|
+
' else if mcvkey_teeth == nil then',
|
291
|
+
' mcvkey_teeth = mcvkey_yoke',
|
292
|
+
'end',
|
259
293
|
'end',
|
260
294
|
'x0_iron_tooth, y0_iron_tooth = 0.0, 0.0',
|
261
295
|
'x0_iron_yoke, y0_iron_yoke = 0.0, 0.0',
|
@@ -324,7 +358,7 @@ class FslRenderer(object):
|
|
324
358
|
self.content.append(
|
325
359
|
'x0_shaft, y0_shaft = x0, y0')
|
326
360
|
|
327
|
-
self.content.append("create_mesh(
|
361
|
+
self.content.append("create_mesh()\n")
|
328
362
|
|
329
363
|
txt = ["if x0_iron_yoke > 0.0 then",
|
330
364
|
" if mcvkey_yoke ~= 'dummy' then",
|
@@ -387,22 +421,24 @@ class FslRenderer(object):
|
|
387
421
|
# angle after mirroring
|
388
422
|
self.content.append('alfa = {}\n'.format(geom.get_alfa()))
|
389
423
|
|
390
|
-
self.content += ['-- rotate',
|
391
|
-
'x1, y1 = {}, {}'.format(
|
392
|
-
geom.start_corners[0][0],
|
393
|
-
geom.start_corners[0][1])] # min xy1
|
394
424
|
if outer:
|
395
|
-
self.content
|
425
|
+
self.content += ['-- rotate',
|
426
|
+
'x1, y1 = {}, {}'.format(
|
427
|
+
geom.start_corners[0][0],
|
428
|
+
geom.start_corners[0][1]), # min xy1
|
429
|
+
'x2, y2 = pr2c(r1, 0.0)']
|
396
430
|
else:
|
397
|
-
self.content
|
398
|
-
|
399
|
-
|
431
|
+
self.content += ['-- rotate',
|
432
|
+
'x1, y1 = pr2c(r1, 0.0)',
|
433
|
+
'x2, y2 = {}, {}'.format(
|
434
|
+
geom.start_corners[1][0],
|
435
|
+
geom.start_corners[1][1])] # min xy1
|
400
436
|
|
401
437
|
if geom.is_mirrored():
|
402
438
|
self.content.append('x3, y3 = pr2c(x2, alfa)')
|
403
439
|
self.content.append('x4, y4 = pr2c(x1, alfa)')
|
404
440
|
elif outer:
|
405
|
-
self.content += ['x3, y3 = pr2c(r1, 2*math.pi/parts
|
441
|
+
self.content += ['x3, y3 = pr2c(r1, 2*math.pi/parts)',
|
406
442
|
'x4, y4 = {}, {}'.format(
|
407
443
|
geom.end_corners[0][0],
|
408
444
|
geom.end_corners[0][1])] # min xy4
|
@@ -410,10 +446,7 @@ class FslRenderer(object):
|
|
410
446
|
self.content += ['x3, y3 = {}, {}'.format(
|
411
447
|
geom.end_corners[-1][0],
|
412
448
|
geom.end_corners[-1][1]), # min xy3
|
413
|
-
'x4, y4 =
|
414
|
-
geom.end_corners[0][0],
|
415
|
-
geom.end_corners[0][1]), # min xy4
|
416
|
-
'def_bcond_vpo(x4, y4, x1, y1)']
|
449
|
+
'x4, y4 = pr2c(r1, 2*math.pi/parts)']
|
417
450
|
|
418
451
|
self.content.append('if parts_gen > 1 then')
|
419
452
|
if geom.corners_dont_match():
|
femagtools/dxfsl/geom.py
CHANGED
@@ -1182,7 +1182,7 @@ class Geometry(object):
|
|
1182
1182
|
nx.set_edge_attributes(self.g, False, 1)
|
1183
1183
|
nx.set_edge_attributes(self.g, False, 2)
|
1184
1184
|
|
1185
|
-
def create_list_of_areas(self, main=False, delete=False):
|
1185
|
+
def create_list_of_areas(self, main=False, delete=False, nolog=True):
|
1186
1186
|
""" return list of areas for each node and their neighbors
|
1187
1187
|
"""
|
1188
1188
|
if delete: # clear list of areas
|
@@ -1193,7 +1193,7 @@ class Geometry(object):
|
|
1193
1193
|
# list already available
|
1194
1194
|
return
|
1195
1195
|
|
1196
|
-
areabuilder = AreaBuilder(geom=self)
|
1196
|
+
areabuilder = AreaBuilder(geom=self, nolog=nolog)
|
1197
1197
|
areabuilder.create_list_of_areas(main=main)
|
1198
1198
|
self.area_list = areabuilder.area_list
|
1199
1199
|
logger.debug("area list created")
|
@@ -3337,6 +3337,31 @@ class Geometry(object):
|
|
3337
3337
|
return [a for a in self.list_of_areas()
|
3338
3338
|
if a.is_type(type)]
|
3339
3339
|
|
3340
|
+
def is_tooth(self, a, windings, wdg_min_dist, wdg_max_dist):
|
3341
|
+
if a.around_windings(windings, self):
|
3342
|
+
if a.close_to_ag:
|
3343
|
+
return True
|
3344
|
+
if self.is_inner:
|
3345
|
+
if greater(a.min_dist, wdg_min_dist, atol=1e-1):
|
3346
|
+
return True
|
3347
|
+
else:
|
3348
|
+
if less(a.max_dist, wdg_max_dist, atol=1e-1):
|
3349
|
+
return True
|
3350
|
+
return False
|
3351
|
+
|
3352
|
+
def between_airgap_and_winding(self, a,
|
3353
|
+
wdg_min_angle,
|
3354
|
+
wdg_max_angle,
|
3355
|
+
wdg_min_dist,
|
3356
|
+
wdg_max_dist):
|
3357
|
+
if greater_equal(a.min_angle, wdg_min_angle) and \
|
3358
|
+
less_equal(a.max_angle, wdg_max_angle):
|
3359
|
+
if self.is_inner:
|
3360
|
+
return less_equal(wdg_max_dist, a.min_dist)
|
3361
|
+
else:
|
3362
|
+
return less_equal(a.max_dist, wdg_min_dist)
|
3363
|
+
return False
|
3364
|
+
|
3340
3365
|
def collect_windings(self):
|
3341
3366
|
logger.debug("begin of collect_windings")
|
3342
3367
|
good_windings = self.get_windings(AREA.TYPE_WINDINGS)
|
@@ -3409,7 +3434,7 @@ class Geometry(object):
|
|
3409
3434
|
max_size, max_w = windings_surface[0]
|
3410
3435
|
for sz, w in windings_surface[1:]:
|
3411
3436
|
logger.debug("winding size = %s", sz)
|
3412
|
-
if sz / max_size < 0.
|
3437
|
+
if sz / max_size < 0.60:
|
3413
3438
|
w.set_type(AREA.TYPE_AIR)
|
3414
3439
|
if sz / max_size < 0.2:
|
3415
3440
|
windings_found -= 1
|
@@ -3459,7 +3484,7 @@ class Geometry(object):
|
|
3459
3484
|
air_areas = [a for a in self.list_of_areas()
|
3460
3485
|
if a.is_type(AREA.TYPE_AIR_OR_IRON)]
|
3461
3486
|
for a in air_areas:
|
3462
|
-
if a.around_windings(windings, self):
|
3487
|
+
if a.around_windings(windings, self) and less(a.min_dist, wdg_max_dist - 0.5):
|
3463
3488
|
logger.debug("Area %s", a.identifier())
|
3464
3489
|
logger.debug(" - air-angle min/max = %s/%s",
|
3465
3490
|
a.min_air_angle,
|
@@ -3481,7 +3506,6 @@ class Geometry(object):
|
|
3481
3506
|
a.close_to_ag):
|
3482
3507
|
a.set_type(AREA.TYPE_AIR) # air
|
3483
3508
|
continue
|
3484
|
-
|
3485
3509
|
a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
|
3486
3510
|
continue
|
3487
3511
|
|
@@ -3510,14 +3534,28 @@ class Geometry(object):
|
|
3510
3534
|
a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
|
3511
3535
|
else:
|
3512
3536
|
logger.debug("#5 not around windings")
|
3513
|
-
|
3537
|
+
if self.between_airgap_and_winding(a,
|
3538
|
+
wdg_min_angle, wdg_max_angle,
|
3539
|
+
wdg_min_dist, wdg_max_dist):
|
3540
|
+
a.set_type(AREA.TYPE_AIR) # air
|
3541
|
+
else:
|
3542
|
+
if self.is_inner:
|
3543
|
+
if greater(a.min_dist, wdg_min_dist, atol=1e-1):
|
3544
|
+
a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
|
3545
|
+
else:
|
3546
|
+
a.set_type(AREA.TYPE_YOKE) # iron shaft (Joch)
|
3547
|
+
else:
|
3548
|
+
if less(a.max_dist, wdg_max_dist, atol=1e-1):
|
3549
|
+
a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
|
3550
|
+
else:
|
3551
|
+
a.set_type(AREA.TYPE_YOKE) # iron shaft (Joch)
|
3514
3552
|
|
3515
3553
|
# yoke or shaft ?
|
3516
3554
|
iron_areas = [a for a in self.list_of_areas()
|
3517
3555
|
if a.is_type(AREA.TYPE_YOKE)]
|
3518
3556
|
for a in iron_areas:
|
3519
3557
|
if a.around_windings(windings, self):
|
3520
|
-
if less(a.min_dist, wdg_max_dist):
|
3558
|
+
if less(a.min_dist, wdg_max_dist - 0.5):
|
3521
3559
|
if less_equal(a.max_dist, wdg_max_dist):
|
3522
3560
|
a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
|
3523
3561
|
else:
|
@@ -3922,6 +3960,15 @@ class Geometry(object):
|
|
3922
3960
|
area.mark_airgap_corners(start_cp, end_cp)
|
3923
3961
|
return
|
3924
3962
|
|
3963
|
+
def get_areas_of_type(self, types=()):
|
3964
|
+
return [area for area in self.list_of_areas()
|
3965
|
+
if area.type in types]
|
3966
|
+
|
3967
|
+
def get_areas_of_irons(self):
|
3968
|
+
return self.get_areas_of_type((AREA.TYPE_IRON,
|
3969
|
+
AREA.TYPE_YOKE,
|
3970
|
+
AREA.TYPE_TOOTH,))
|
3971
|
+
|
3925
3972
|
def num_areas_of_type(self, types=()):
|
3926
3973
|
return len([area for area in self.list_of_areas()
|
3927
3974
|
if area.type in types])
|
@@ -4268,6 +4315,16 @@ class Geometry(object):
|
|
4268
4315
|
for e in self.elements():
|
4269
4316
|
e.adjust_points()
|
4270
4317
|
|
4318
|
+
def split_with_point(self, p):
|
4319
|
+
for e in self.elements(Shape):
|
4320
|
+
elements = e.split([p])
|
4321
|
+
if elements:
|
4322
|
+
self.remove_edge(e)
|
4323
|
+
for e in elements:
|
4324
|
+
self.add_element(e, rtol=self.rtol, atol=self.atol)
|
4325
|
+
return True
|
4326
|
+
return False
|
4327
|
+
|
4271
4328
|
def split_and_get_intersect_points(self, el, aktion=True, include_end=True):
|
4272
4329
|
logger.debug("begin of split_and_get_intersect_points")
|
4273
4330
|
rtol = 1e-03
|
@@ -4424,38 +4481,6 @@ class Geometry(object):
|
|
4424
4481
|
builder = AreaBuilder(geom=self)
|
4425
4482
|
return builder.create_inner_corner_auxiliary_areas(startangle, endangle)
|
4426
4483
|
|
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
4484
|
def adjust_outer_hull_for_symmetry(self):
|
4460
4485
|
logger.debug("adjust_outer_hull_for_symmetry()")
|
4461
4486
|
areas = self.list_of_areas()
|
@@ -4778,6 +4803,52 @@ class Geometry(object):
|
|
4778
4803
|
return
|
4779
4804
|
logger.warning("WARNING: airgap connecting nodes do not aline")
|
4780
4805
|
|
4806
|
+
def remove_area(self, area):
|
4807
|
+
logger.debug("Remove Area %s", area.identifier())
|
4808
|
+
touching_areas = [(a.surface, a) for a in self.list_of_areas()
|
4809
|
+
if a.id != area.id and a.is_touching(area)]
|
4810
|
+
if not touching_areas:
|
4811
|
+
self.remove_edges(area.area)
|
4812
|
+
return
|
4813
|
+
touching_areas.sort(reverse=True)
|
4814
|
+
sz, touching_a = touching_areas[0]
|
4815
|
+
for e in area.area:
|
4816
|
+
if touching_a.is_element_in_area(e):
|
4817
|
+
self.remove_edge(e)
|
4818
|
+
|
4819
|
+
def remove_tiny_air_areas(self):
|
4820
|
+
logger.debug("remove_tiny_air_areas()")
|
4821
|
+
air_areas = [a for a in self.list_of_areas() if a.is_air()]
|
4822
|
+
if not air_areas:
|
4823
|
+
return False
|
4824
|
+
|
4825
|
+
def is_in_touch(air, area_list):
|
4826
|
+
for a in area_list:
|
4827
|
+
if air.is_touching(a):
|
4828
|
+
return True
|
4829
|
+
if air.is_inside(a, self):
|
4830
|
+
return True
|
4831
|
+
return False
|
4832
|
+
|
4833
|
+
areas = [a for a in self.list_of_areas() if a.is_winding() or a.is_magnet()]
|
4834
|
+
if not areas:
|
4835
|
+
return False
|
4836
|
+
|
4837
|
+
tiny_areas = [a for a in air_areas if not is_in_touch(a, areas)]
|
4838
|
+
geom_surface = self.area_size()
|
4839
|
+
angle_areas = [a for a in tiny_areas
|
4840
|
+
if (a.close_to_startangle or a.close_to_endangle)]
|
4841
|
+
#inside_areas = [a for a in tiny_areas
|
4842
|
+
# if not (a.close_to_startangle or a.close_to_endangle) and \
|
4843
|
+
# a.get_area_size() < geom_surface / 200]
|
4844
|
+
tiny_areas = angle_areas
|
4845
|
+
if not tiny_areas:
|
4846
|
+
return False
|
4847
|
+
|
4848
|
+
for a in tiny_areas:
|
4849
|
+
self.remove_area(a)
|
4850
|
+
return True
|
4851
|
+
|
4781
4852
|
def print_nodes(self):
|
4782
4853
|
print("=== List of Nodes ({}) ===".format(self.number_of_nodes()))
|
4783
4854
|
for n in self.g.nodes():
|